/* Copyright (c) 2010, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include struct dtmf { struct mutex lock; struct audio_client *ac; struct msm_dtmf_config cfg; }; static long dtmf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct dtmf *dtmf = file->private_data; int rc = 0; mutex_lock(&dtmf->lock); switch (cmd) { case AUDIO_START: { pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__); if (dtmf->ac) { pr_err("[%s:%s] active session already existing\n", __MM_FILE__, __func__); rc = -EBUSY; } else { dtmf->ac = q6audio_open_dtmf(48000, 2, 0); if (!dtmf->ac) rc = -ENOMEM; } break; } case AUDIO_PLAY_DTMF: { rc = copy_from_user((void *)&dtmf->cfg, (void *)arg, sizeof(struct msm_dtmf_config)); pr_debug("[%s:%s] PLAY_DTMF: high = %d, low = %d\n", __MM_FILE__, __func__, dtmf->cfg.dtmf_hi, dtmf->cfg.dtmf_low); rc = q6audio_play_dtmf(dtmf->ac, dtmf->cfg.dtmf_hi, dtmf->cfg.dtmf_low, dtmf->cfg.duration, dtmf->cfg.rx_gain); if (rc) { pr_err("[%s:%s] DTMF_START failed\n", __MM_FILE__, __func__); break; } break; } default: rc = -EINVAL; } mutex_unlock(&dtmf->lock); pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc) ; return rc; } static int dtmf_open(struct inode *inode, struct file *file) { int rc = 0; struct dtmf *dtmf; pr_info("[%s:%s] open\n", __MM_FILE__, __func__); dtmf = kzalloc(sizeof(struct dtmf), GFP_KERNEL); if (!dtmf) return -ENOMEM; mutex_init(&dtmf->lock); file->private_data = dtmf; return rc; } static int dtmf_release(struct inode *inode, struct file *file) { struct dtmf *dtmf = file->private_data; if (dtmf->ac) q6audio_close(dtmf->ac); kfree(dtmf); pr_info("[%s:%s] release\n", __MM_FILE__, __func__); return 0; } static const struct file_operations dtmf_fops = { .owner = THIS_MODULE, .open = dtmf_open, .release = dtmf_release, .unlocked_ioctl = dtmf_ioctl, }; struct miscdevice dtmf_misc = { .minor = MISC_DYNAMIC_MINOR, .name = "msm_dtmf", .fops = &dtmf_fops, }; static int __init dtmf_init(void) { return misc_register(&dtmf_misc); } device_initcall(dtmf_init);