1 /* 2 * Jack abstraction layer 3 * 4 * Copyright 2008 Wolfson Microelectronics 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 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 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <linux/input.h> 23 #include <sound/jack.h> 24 #include <sound/core.h> 25 26 static int snd_jack_dev_free(struct snd_device *device) 27 { 28 struct snd_jack *jack = device->device_data; 29 30 /* If the input device is registered with the input subsystem 31 * then we need to use a different deallocator. */ 32 if (jack->registered) 33 input_unregister_device(jack->input_dev); 34 else 35 input_free_device(jack->input_dev); 36 37 kfree(jack); 38 39 return 0; 40 } 41 42 static int snd_jack_dev_register(struct snd_device *device) 43 { 44 struct snd_jack *jack = device->device_data; 45 struct snd_card *card = device->card; 46 int err; 47 48 snprintf(jack->name, sizeof(jack->name), "%s %s", 49 card->longname, jack->id); 50 jack->input_dev->name = jack->name; 51 52 /* Default to the sound card device. */ 53 if (!jack->input_dev->dev.parent) 54 jack->input_dev->dev.parent = card->dev; 55 56 err = input_register_device(jack->input_dev); 57 if (err == 0) 58 jack->registered = 1; 59 60 return err; 61 } 62 63 /** 64 * snd_jack_new - Create a new jack 65 * @card: the card instance 66 * @id: an identifying string for this jack 67 * @type: a bitmask of enum snd_jack_type values that can be detected by 68 * this jack 69 * @jjack: Used to provide the allocated jack object to the caller. 70 * 71 * Creates a new jack object. 72 * 73 * Returns zero if successful, or a negative error code on failure. 74 * On success jjack will be initialised. 75 */ 76 int snd_jack_new(struct snd_card *card, const char *id, int type, 77 struct snd_jack **jjack) 78 { 79 struct snd_jack *jack; 80 int err; 81 static struct snd_device_ops ops = { 82 .dev_free = snd_jack_dev_free, 83 .dev_register = snd_jack_dev_register, 84 }; 85 86 jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); 87 if (jack == NULL) 88 return -ENOMEM; 89 90 jack->id = id; 91 92 jack->input_dev = input_allocate_device(); 93 if (jack->input_dev == NULL) { 94 err = -ENOMEM; 95 goto fail_input; 96 } 97 98 jack->input_dev->phys = "ALSA"; 99 100 jack->type = type; 101 102 if (type & SND_JACK_HEADPHONE) 103 input_set_capability(jack->input_dev, EV_SW, 104 SW_HEADPHONE_INSERT); 105 if (type & SND_JACK_MICROPHONE) 106 input_set_capability(jack->input_dev, EV_SW, 107 SW_MICROPHONE_INSERT); 108 109 err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); 110 if (err < 0) 111 goto fail_input; 112 113 *jjack = jack; 114 115 return 0; 116 117 fail_input: 118 input_free_device(jack->input_dev); 119 kfree(jack); 120 return err; 121 } 122 EXPORT_SYMBOL(snd_jack_new); 123 124 /** 125 * snd_jack_set_parent - Set the parent device for a jack 126 * 127 * @jack: The jack to configure 128 * @parent: The device to set as parent for the jack. 129 * 130 * Set the parent for the jack input device in the device tree. This 131 * function is only valid prior to registration of the jack. If no 132 * parent is configured then the parent device will be the sound card. 133 */ 134 void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) 135 { 136 WARN_ON(jack->registered); 137 138 jack->input_dev->dev.parent = parent; 139 } 140 EXPORT_SYMBOL(snd_jack_set_parent); 141 142 /** 143 * snd_jack_report - Report the current status of a jack 144 * 145 * @jack: The jack to report status for 146 * @status: The current status of the jack 147 */ 148 void snd_jack_report(struct snd_jack *jack, int status) 149 { 150 if (!jack) 151 return; 152 153 if (jack->type & SND_JACK_HEADPHONE) 154 input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, 155 status & SND_JACK_HEADPHONE); 156 if (jack->type & SND_JACK_MICROPHONE) 157 input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, 158 status & SND_JACK_MICROPHONE); 159 160 input_sync(jack->input_dev); 161 } 162 EXPORT_SYMBOL(snd_jack_report); 163 164 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 165 MODULE_DESCRIPTION("Jack detection support for ALSA"); 166 MODULE_LICENSE("GPL"); 167