Share Pastebin
Guest
Public paste!

Untitled

By: a guest | Sep 2nd, 2010 | Syntax: None | Size: 10.10 KB | Hits: 32 | Expires: Never
Copy text to clipboard
  1. /* arch/arm/mach-msm/qdsp5/snd.c
  2.  *
  3.  * interface to "snd" service on the baseband cpu
  4.  *
  5.  * Copyright (C) 2008 HTC Corporation
  6.  *
  7.  * This software is licensed under the terms of the GNU General Public
  8.  * License version 2, as published by the Free Software Foundation, and
  9.  * may be copied, distributed, and modified under those terms.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  */
  17.  
  18. #include <linux/module.h>
  19. #include <linux/fs.h>
  20. #include <linux/miscdevice.h>
  21. #include <linux/uaccess.h>
  22. #include <linux/kthread.h>
  23. #include <linux/delay.h>
  24. #include <linux/msm_audio.h>
  25.  
  26. #include <asm/gpio.h>
  27. #include <asm/atomic.h>
  28. #include <asm/ioctls.h>
  29. #include <mach/board.h>
  30. #include <mach/msm_rpcrouter.h>
  31. #include <mach/htc_headset.h>
  32. #include <asm/mach-types.h>
  33. #include <mach/amss_para.h>
  34. #include <linux/dma-mapping.h>
  35.  
  36. #include <asm/ioctls.h>
  37. #include <mach/msm_adsp.h>
  38. #include <mach/msm_iomap.h>
  39.  
  40. #define RPC_SND_PROG    0x30000002
  41.  
  42. /* Taken from android hardware/msm7k/libaudio/AudioHardware.h
  43.  * Used for SND_SET_DEVICE ioctl
  44.  */
  45. #define SND_DEVICE_HANDSET 0
  46. #define SND_DEVICE_SPEAKER 1
  47. #define SND_DEVICE_HEADSET 2
  48. #define SND_DEVICE_BT 3
  49. #define SND_DEVICE_CARKIT 4
  50. #define SND_DEVICE_TTY_FULL 5
  51. #define SND_DEVICE_TTY_VCO 6
  52. #define SND_DEVICE_TTY_HCO 7
  53. #define SND_DEVICE_NO_MIC_HEADSET 8
  54. #define SND_DEVICE_FM_HEADSET 9
  55. #define SND_DEVICE_HEADSET_AND_SPEAKER 10
  56. #define SND_DEVICE_FM_SPEAKER 11
  57. #define SND_DEVICE_BT_EC_OFF 12
  58.  
  59. struct snd_ctxt {
  60.         struct mutex lock;
  61.         int opened;
  62.         struct msm_rpc_endpoint *ept;
  63.         struct msm_snd_endpoints *snd_epts;
  64. };
  65.  
  66. static struct snd_ctxt the_snd;
  67. static int force_headset=0;
  68. module_param_named(force_headset, force_headset, int, S_IRUGO | S_IWUSR | S_IWGRP);
  69.  
  70. static int stupid_android=1;
  71. module_param_named(stupid_android, stupid_android, int, S_IRUGO | S_IWUSR | S_IWGRP);
  72.  
  73.  
  74. struct rpc_snd_set_device_args {
  75.         uint32_t device;
  76.         uint32_t ear_mute;
  77.         uint32_t mic_mute;
  78.  
  79.         uint32_t cb_func;
  80.         uint32_t client_data;
  81. };
  82.  
  83. struct rpc_snd_set_volume_args {
  84.         uint32_t device;
  85.         uint32_t method;
  86.         uint32_t volume;
  87.  
  88.         uint32_t cb_func;
  89.         uint32_t client_data;
  90. };
  91.  
  92. struct snd_set_device_msg {
  93.         struct rpc_request_hdr hdr;
  94.         struct rpc_snd_set_device_args args;
  95. };
  96.  
  97. struct snd_set_volume_msg {
  98.         struct rpc_request_hdr hdr;
  99.         struct rpc_snd_set_volume_args args;
  100. };
  101.  
  102. struct snd_endpoint *get_snd_endpoints(int *size);
  103.  
  104. static inline int check_mute(int mute)
  105. {
  106.         return (mute == SND_MUTE_MUTED ||
  107.                 mute == SND_MUTE_UNMUTED) ? 0 : -EINVAL;
  108. }
  109.  
  110. static int get_endpoint(struct snd_ctxt *snd, unsigned long arg)
  111. {
  112.         int rc = 0, index;
  113.         struct msm_snd_endpoint ept;
  114.  
  115.         if (copy_from_user(&ept, (void __user *)arg, sizeof(ept))) {
  116.                 pr_err("snd_ioctl get endpoint: invalid read pointer.\n");
  117.                 return -EFAULT;
  118.         }
  119.  
  120.         index = ept.id;
  121.         if (index < 0 || index >= snd->snd_epts->num) {
  122.                 pr_err("snd_ioctl get endpoint: invalid index!\n");
  123.                 return -EINVAL;
  124.         }
  125.  
  126.         ept.id = snd->snd_epts->endpoints[index].id;
  127.         strncpy(ept.name,
  128.                 snd->snd_epts->endpoints[index].name,
  129.                 sizeof(ept.name));
  130.  
  131.         if (copy_to_user((void __user *)arg, &ept, sizeof(ept))) {
  132.                 pr_err("snd_ioctl get endpoint: invalid write pointer.\n");
  133.                 rc = -EFAULT;
  134.         }
  135.  
  136.         return rc;
  137. }
  138.  
  139. int turn_mic_bias_on(int on);
  140. void platform_vol(int vol);
  141.  
  142. void snd_set_adie_parameters (int device) {
  143. /*
  144.         int UpdateAudioMethod = 0;
  145.         int UpdateForceADIEAwake = 0;
  146.         uint32_t setval = 2;
  147.         uint32_t adie;  
  148.         switch(device) {
  149.                 case 0:         // Phone
  150.                         UpdateAudioMethod = 1;
  151.                 break;
  152.                 case 1:         // Normal
  153.                         UpdateAudioMethod = 1;
  154.                 break;
  155.                 case 2:         // Headset
  156.                 break;
  157.                
  158.                 case 3:         // BT Headset
  159.                 break;
  160.                
  161.                 case 11:        // FM
  162.                         UpdateAudioMethod = 1;
  163.                         UpdateForceADIEAwake = 1;
  164.                 break;
  165.                 default:
  166.                 break;
  167.         }
  168.         setval += (UpdateAudioMethod*4 + UpdateForceADIEAwake*8);
  169.  
  170.         adie = readl(MSM_SHARED_RAM_BASE + 0xfc0d0);
  171.         if(adie != setval) {
  172.                 pr_info("snd_set_adie_parameters: Set adie to %u\n", setval);
  173.                 writel(setval, MSM_SHARED_RAM_BASE + 0xfc0d0);
  174.         }
  175. */
  176. }
  177.  
  178. //from external.c
  179. void enable_speaker(void);
  180. void disable_speaker(void);
  181. void speaker_vol(int);
  182.  
  183. void snd_set_device(int device,int ear_mute, int mic_mute) {
  184.         struct snd_ctxt *snd = &the_snd;
  185.         struct snd_set_device_msg dmsg;
  186.         if(force_headset && (force_headset==2 || headset_plugged()))
  187.                 device=2;
  188.         switch(__machine_arch_type) {
  189.                 case MACH_TYPE_HTCTOPAZ:
  190.                         snd_set_adie_parameters(device);
  191.                         break;
  192.         }
  193.         dmsg.args.device = cpu_to_be32(device);
  194.         dmsg.args.ear_mute = cpu_to_be32(ear_mute);
  195.         dmsg.args.mic_mute = cpu_to_be32(mic_mute);
  196.         dmsg.args.cb_func = -1;
  197.         dmsg.args.client_data = 0;
  198.         if((!ear_mute || stupid_android) && device==1)
  199.                 enable_speaker();
  200.         else
  201.                 disable_speaker();
  202.  
  203.         mic_mute=SND_MUTE_UNMUTED;
  204.         if(mic_mute==SND_MUTE_UNMUTED)
  205.                 turn_mic_bias_on(1);
  206.         else
  207.                 turn_mic_bias_on(0);
  208.         pr_info("snd_set_device %d %d %d\n", device,
  209.                                          ear_mute, mic_mute);
  210.         mic_mute=0;
  211.  
  212.         if(!snd->ept) {
  213.                 pr_err("No sound endpoint found, can't set snd_device");
  214.                 return;
  215.         }
  216.         msm_rpc_call(snd->ept,
  217.                 amss_get_num_value(SND_SET_DEVICE_PROC),
  218.                 &dmsg, sizeof(dmsg), 5 * HZ);
  219.  
  220. }
  221. EXPORT_SYMBOL(snd_set_device);
  222.  
  223. /* From external.c */
  224. void headphone_amp_power(int status);
  225.  
  226. static long snd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  227. {
  228.         struct snd_set_device_msg dmsg;
  229.         struct snd_set_volume_msg vmsg;
  230.         struct msm_snd_device_config dev;
  231.         struct msm_snd_volume_config vol;
  232.         struct snd_ctxt *snd = file->private_data;
  233.         int rc = 0;
  234.  
  235.         mutex_lock(&snd->lock);
  236.         switch (cmd) {
  237.         case SND_SET_DEVICE:
  238.                 if (copy_from_user(&dev, (void __user *) arg, sizeof(dev))) {
  239.                         pr_err("snd_ioctl set device: invalid pointer.\n");
  240.                         rc = -EFAULT;
  241.                         break;
  242.                 }
  243.                 printk("snd_ioctl set_device: device %d\n", dev.device);
  244.  
  245.                 if (check_mute(dev.ear_mute) ||
  246.                                 check_mute(dev.mic_mute) ) {
  247.                         pr_err("snd_ioctl set device: invalid mute status.\n");
  248.                         rc = -EINVAL;
  249.                         break;
  250.                 }
  251.  
  252.                 /* Headphones/headset need to turn on amp through GPIO */
  253.                 headphone_amp_power(
  254.                                 (dev.device == SND_DEVICE_HEADSET) ||
  255.                                 (dev.device == SND_DEVICE_NO_MIC_HEADSET)
  256.                                 );
  257.  
  258.                 /* Headset output (2) is the working output for headphones, not 8 */
  259.                 if (dev.device == SND_DEVICE_NO_MIC_HEADSET)
  260.                         dev.device = SND_DEVICE_HEADSET;
  261.  
  262.                 snd_set_device(dev.device, dev.ear_mute, dev.mic_mute);
  263.                 break;
  264.  
  265.         case SND_SET_VOLUME:
  266.  
  267.                 if (copy_from_user(&vol, (void __user *) arg, sizeof(vol))) {
  268.                         pr_err("snd_ioctl set volume: invalid pointer.\n");
  269.                         rc = -EFAULT;
  270.                         break;
  271.                 }
  272.  
  273. #if defined(CONFIG_MSM_AMSS_VERSION_WINCE)
  274.                 switch(__machine_arch_type) {
  275.                         case MACH_TYPE_HTCTOPAZ:
  276.                         case MACH_TYPE_HTCRHODIUM:
  277.                                 pr_err("buggy program %s is calling snd_set_volume with dev=%d != 0x11\n", current->comm, vol.device);
  278.                                 vol.device = 0x11;
  279.                                 break;
  280.                         case MACH_TYPE_HTCRAPHAEL:
  281.                         case MACH_TYPE_HTCDIAMOND_CDMA:
  282.                         case MACH_TYPE_HTCDIAMOND:
  283.                         case MACH_TYPE_HTCBLACKSTONE:
  284.                         case MACH_TYPE_HTCRAPHAEL_CDMA:
  285.                         case MACH_TYPE_HTCRAPHAEL_CDMA500:
  286.                                 pr_err("buggy program %s is calling snd_set_volume with dev=%d != 0xd\n", current->comm, vol.device);
  287.                                 vol.device = 0xd;
  288.                                 break;
  289.                         default:
  290.                                 printk(KERN_ERR "Unsupported device for snd_set_device driver\n");
  291.                                 break;
  292.                 }
  293. #endif
  294.                 if(vol.device==1)
  295.                         speaker_vol(vol.volume);
  296.                 platform_vol(vol.volume);
  297.                 vmsg.args.device = cpu_to_be32(vol.device);
  298.                 vmsg.args.method = cpu_to_be32(vol.method);
  299.                 if (vol.method != SND_METHOD_VOICE && vol.method != SND_METHOD_AUDIO) {
  300.                         pr_err("snd_ioctl set volume: invalid method.\n");
  301.                         rc = -EINVAL;
  302.                         break;
  303.                 }
  304.  
  305.                 vmsg.args.volume = cpu_to_be32(vol.volume);
  306.                 vmsg.args.cb_func = -1;
  307.                 vmsg.args.client_data = 0;
  308.  
  309.                 pr_info("snd_set_volume %d %d %d\n", vol.device,
  310.                                                 vol.method, vol.volume);
  311.  
  312.                 rc = msm_rpc_call(snd->ept,
  313.                         amss_get_num_value(SND_SET_VOLUME_PROC),
  314.                         &vmsg, sizeof(vmsg), 5 * HZ);
  315.  
  316.                                        
  317.         case SND_GET_NUM_ENDPOINTS:
  318.                 if (copy_to_user((void __user *)arg,
  319.                                 &snd->snd_epts->num, sizeof(unsigned))) {
  320.                         pr_err("snd_ioctl get endpoint: invalid pointer.\n");
  321.                         rc = -EFAULT;
  322.                 }
  323.                 break;
  324.  
  325.         case SND_GET_ENDPOINT:
  326.                 rc = get_endpoint(snd, arg);
  327.                 break;
  328.  
  329.         default:
  330.                 pr_err("snd_ioctl unknown command.\n");
  331.                 rc = -EINVAL;
  332.                 break;
  333.         }
  334.         mutex_unlock(&snd->lock);
  335.  
  336.         return rc;
  337. }
  338.  
  339. static int snd_release(struct inode *inode, struct file *file)
  340. {
  341.         struct snd_ctxt *snd = file->private_data;
  342.  
  343.         mutex_lock(&snd->lock);
  344.         snd->opened--;
  345.         mutex_unlock(&snd->lock);
  346.         return 0;
  347. }
  348.  
  349. int snd_ini() {
  350.  
  351.         struct snd_ctxt *snd = &the_snd;
  352.         int rc = 0;
  353.  
  354.         mutex_lock(&snd->lock);
  355.         if (snd->opened == 0) {
  356.                 if (snd->ept == NULL) {
  357.                         snd->ept = msm_rpc_connect(
  358.                                                 RPC_SND_PROG,
  359.                                                 amss_get_num_value(RPC_SND_VERS),
  360.                                                 MSM_RPC_UNINTERRUPTIBLE);
  361.                         if (IS_ERR(snd->ept)) {
  362.                                 rc = PTR_ERR(snd->ept);
  363.                                 snd->ept = NULL;
  364.                                 pr_err("snd: failed to connect snd svc\n");
  365.                                 goto err;
  366.                         }
  367.                 }
  368.         } else {
  369.                 pr_err("snd already opened.\n");
  370.         }
  371.         snd->opened++;
  372.  
  373. err:
  374.         mutex_unlock(&snd->lock);
  375.         return rc;
  376. }
  377.  
  378. static int snd_open(struct inode *inode, struct file *file)
  379. {
  380.         int rc = 0;
  381.         struct snd_ctxt *snd = &the_snd;
  382.         rc = snd_ini();
  383.         if(rc)
  384.                 return rc;
  385.         file->private_data=snd;
  386.         return rc;
  387. }
  388.  
  389. static struct file_operations snd_fops = {
  390.         .owner          = THIS_MODULE,
  391.         .open           = snd_open,
  392.         .release        = snd_release,
  393.         .unlocked_ioctl = snd_ioctl,
  394. };
  395.  
  396. struct miscdevice snd_misc = {
  397.         .minor  = MISC_DYNAMIC_MINOR,
  398.         .name   = "msm_snd",
  399.         .fops   = &snd_fops,
  400. };
  401.  
  402. static int snd_probe(struct platform_device *pdev)
  403. {
  404.         struct snd_ctxt *snd = &the_snd;
  405.         mutex_init(&snd->lock);
  406.         snd->snd_epts = (struct msm_snd_endpoints *)pdev->dev.platform_data;
  407.         return misc_register(&snd_misc);
  408. }
  409.  
  410. static struct platform_driver snd_plat_driver = {
  411.         .probe = snd_probe,
  412.         .driver = {
  413.                 .name = "msm_snd",
  414.                 .owner = THIS_MODULE,
  415.         },
  416. };
  417.  
  418. static int __init snd_init(void)
  419. {
  420.         return platform_driver_register(&snd_plat_driver);
  421. }
  422.  
  423. module_init(snd_init);