📄 patch_cnxthsf.c
字号:
/* * HD audio interface patch for Conexant HSF modems * * Copyright (c) 2005-2006 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. LINUXANT 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. * LINUXANT 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 Company, its customers, or any third parties for any reason * whatsoever, and LINUXANT 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 <sound/driver.h>#include <linux/init.h>#include <sound/core.h>#include "hda_codec.h"#include "hda_local.h"#if defined(__i386__)#define __shimcall__ __attribute__((regparm(0)))#define __kernelcall__#define __kernelcallregparm__ __attribute__((regparm(3)))#define __kernelcallstkparm__ __attribute__((regparm(0)))#else#define __shimcall__#define __kernelcall__#define __kernelcallregparm__#define __kernelcallstkparm__#endifstruct cnxthsf_spec { void *pDevNode; unsigned int stream_tags[2]; int do_prepare[2]; void (*cbHdaEvent)(void *Context, unsigned int res) __shimcall__; void *cbHdaEventContext; unsigned char cbHdaTag; struct hda_pcm pcm;};static int cnxthsf_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, unsigned int format, snd_pcm_substream_t *substream){ struct cnxthsf_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->stream_tags[substream->stream] = stream_tag; return 0;}static int cnxthsf_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, snd_pcm_substream_t *substream){ static unsigned int rates[] = { 16000 }; static snd_pcm_hw_constraint_list_t hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, };//printk(KERN_DEBUG"%s: codec=%p substream=%p\n", __FUNCTION__, codec, substream);#if 0 // XXX //substream->runtime->hw.periods_min = 1; substream->runtime->hw.period_bytes_min = 256; //4096;#endif return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);}#if 0static int cnxthsf_pcm_close(struct hda_pcm_stream *info, struct hda_codec *codec, snd_pcm_substream_t *substream){}static int cnxthsf_pcm_cleanup(struct hda_pcm_stream *info, struct hda_codec *codec, snd_pcm_substream_t *substream){}#endifstatic struct hda_pcm_stream cnxthsf_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 = cnxthsf_pcm_open, //.close = cnxthsf_pcm_close, .prepare = cnxthsf_pcm_prepare, //.cleanup = cnxthsf_pcm_cleanup, },};static int cnxthsf_build_pcms(struct hda_codec *codec){ struct cnxthsf_spec *spec = codec->spec; struct hda_pcm *info = &spec->pcm;//printk(KERN_DEBUG"%s: codec=%p mfg=%d\n", __FUNCTION__, codec, codec->mfg); cnxthsf_pcm.nid = codec->mfg; codec->num_pcms = 1; codec->pcm_info = info; info->name = "HSF Modem"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cnxthsf_pcm; info->stream[SNDRV_PCM_STREAM_CAPTURE] = cnxthsf_pcm; info->is_modem = 1; return 0;}static int cnxthsf_init(struct hda_codec *codec){ int ret; struct cnxthsf_spec *spec = codec->spec; int (*cnxthwhda_probe)(void *codec, struct device *hwDev, void **ppDevNode);//printk(KERN_DEBUG"%s: codec=%p\n", __FUNCTION__, codec); cnxthwhda_probe = (void*)symbol_request(cnxthwhda_probe); if(!cnxthwhda_probe) { printk(KERN_ERR"%s: symbol_request(cnxthwhda_probe) failed\n", __FUNCTION__); return -ENOENT; } ret = cnxthwhda_probe(codec, codec->bus->card->dev, &spec->pDevNode); if(ret) { printk(KERN_ERR"%s: cnxthwhda_probe() failed: %d\n", __FUNCTION__, ret); symbol_put(cnxthwhda_probe); return ret; } return ret;}static int cnxthsf_exit(struct hda_codec *codec){ struct cnxthsf_spec *spec = codec->spec;//printk(KERN_DEBUG"%s: codec=%p spec=%p\n", __FUNCTION__, codec, spec); if(spec && spec->pDevNode) { void (*cnxthwhda_remove)(void *ptr); cnxthwhda_remove = (void*)symbol_request(cnxthwhda_remove); if(cnxthwhda_remove) { cnxthwhda_remove(spec->pDevNode); spec->pDevNode = 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 cnxthsf_free(struct hda_codec *codec){ struct cnxthsf_spec *spec = codec->spec;//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)); kfree(spec); }}static void cnxthsf_unsol_event(struct hda_codec *codec, unsigned int res){ struct cnxthsf_spec *spec = codec->spec; //printk(KERN_DEBUG"%s: codec=%p res=0x%02x spec=%p cbHdaEvent=%p\n", __FUNCTION__, codec, res, spec, spec->cbHdaEvent); if(spec && spec->cbHdaEvent) { if(((res >> 26) & 0x3f) == spec->cbHdaTag) { //printk(KERN_DEBUG"%s: res=0x%02x cbHdaEvent=%p\n", __FUNCTION__, res, spec->cbHdaEvent);// printk(KERN_DEBUG"%s: calling cbHdaEvent=%p ctx=%p\n", __FUNCTION__, spec->cbHdaEvent, spec->cbHdaEventContext); spec->cbHdaEvent(spec->cbHdaEventContext, res); } else { printk(KERN_DEBUG"%s: ignoring res=0x08%x\n", __FUNCTION__, res); } }}static int cnxthsf_suspend(struct hda_codec *codec, pm_message_t state){ struct cnxthsf_spec *spec = codec->spec; int (*cnxthwhda_suspend)(void *devnode, pm_message_t state); int ret; printk(KERN_DEBUG"%s: codec=%p spec=%p state=0x%x\n", __FUNCTION__, codec, spec, *((u32 *)&state)); if(!spec || !spec->pDevNode) { return -EINVAL; } cnxthwhda_suspend = (void*)symbol_request(cnxthwhda_suspend); if(!cnxthwhda_suspend) { printk(KERN_ERR"%s: symbol_request(cnxthwhda_suspend) failed\n", __FUNCTION__); return -ENOSYS; } ret = cnxthwhda_suspend(spec->pDevNode, state); symbol_put(cnxthwhda_suspend); return ret;}static int cnxthsf_resume (struct hda_codec *codec){ struct cnxthsf_spec *spec = codec->spec; int (*cnxthwhda_resume)(void *devnode); int ret; printk(KERN_DEBUG"%s: codec=%p spec=%p\n", __FUNCTION__, codec, spec); if(!spec || !spec->pDevNode) { return -EINVAL; } cnxthwhda_resume = (void*)symbol_request(cnxthwhda_resume); if(!cnxthwhda_resume) { printk(KERN_ERR"%s: symbol_request(cnxthwhda_resume) failed\n", __FUNCTION__); return -ENOSYS; } ret = cnxthwhda_resume(spec->pDevNode); symbol_put(cnxthwhda_resume); return ret;}static struct hda_codec_ops cnxthsf_patch_ops = { .build_pcms = cnxthsf_build_pcms, .init = cnxthsf_init, .exit = cnxthsf_exit, .free = cnxthsf_free, .unsol_event = cnxthsf_unsol_event,#ifdef CONFIG_PM .suspend = cnxthsf_suspend, .resume = cnxthsf_resume,#endif}; static int patch_cnxthsf(struct hda_codec *codec){ struct cnxthsf_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 = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; codec->spec = spec; codec->patch_ops = cnxthsf_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;}struct hda_codec_preset snd_hda_preset_cnxthsf[] = { { .id = 0x14f10000, .mask = 0xffff0000, .mfg = 2, .name = "HSF", .patch = patch_cnxthsf }, {}};typedef unsigned long ULONG, *PULONG;#include "../../include/oshda.h"__shimcall__unsigned int OsHdaCodecGetAddr(PHDAOSHAL pHdaOsHal){ return ((struct hda_codec *)pHdaOsHal->hda_codec)->addr;}EXPORT_SYMBOL(OsHdaCodecGetAddr);__shimcall__unsigned int OsHdaCodecGetVendorId(PHDAOSHAL pHdaOsHal){ return ((struct hda_codec *)pHdaOsHal->hda_codec)->vendor_id;}EXPORT_SYMBOL(OsHdaCodecGetVendorId);__shimcall__unsigned int OsHdaCodecGetSubsystemId(PHDAOSHAL pHdaOsHal){ return ((struct hda_codec *)pHdaOsHal->hda_codec)->subsystem_id;}EXPORT_SYMBOL(OsHdaCodecGetSubsystemId);__shimcall__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -