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 <linux/slab.h> 24 #include <sound/jack.h> 25 #include <sound/core.h> 26 27 static int jack_types[] = { 28 SW_HEADPHONE_INSERT, 29 SW_MICROPHONE_INSERT, 30 SW_LINEOUT_INSERT, 31 SW_JACK_PHYSICAL_INSERT, 32 SW_VIDEOOUT_INSERT, 33 }; 34 35 static int snd_jack_dev_free(struct snd_device *device) 36 { 37 struct snd_jack *jack = device->device_data; 38 39 if (jack->private_free) 40 jack->private_free(jack); 41 42 /* If the input device is registered with the input subsystem 43 * then we need to use a different deallocator. */ 44 if (jack->registered) 45 input_unregister_device(jack->input_dev); 46 else 47 input_free_device(jack->input_dev); 48 49 kfree(jack->id); 50 kfree(jack); 51 52 return 0; 53 } 54 55 static int snd_jack_dev_register(struct snd_device *device) 56 { 57 struct snd_jack *jack = device->device_data; 58 struct snd_card *card = device->card; 59 int err; 60 61 snprintf(jack->name, sizeof(jack->name), "%s %s", 62 card->shortname, jack->id); 63 jack->input_dev->name = jack->name; 64 65 /* Default to the sound card device. */ 66 if (!jack->input_dev->dev.parent) 67 jack->input_dev->dev.parent = snd_card_get_device_link(card); 68 69 err = input_register_device(jack->input_dev); 70 if (err == 0) 71 jack->registered = 1; 72 73 return err; 74 } 75 76 /** 77 * snd_jack_new - Create a new jack 78 * @card: the card instance 79 * @id: an identifying string for this jack 80 * @type: a bitmask of enum snd_jack_type values that can be detected by 81 * this jack 82 * @jjack: Used to provide the allocated jack object to the caller. 83 * 84 * Creates a new jack object. 85 * 86 * Returns zero if successful, or a negative error code on failure. 87 * On success jjack will be initialised. 88 */ 89 int snd_jack_new(struct snd_card *card, const char *id, int type, 90 struct snd_jack **jjack) 91 { 92 struct snd_jack *jack; 93 int err; 94 int i; 95 static struct snd_device_ops ops = { 96 .dev_free = snd_jack_dev_free, 97 .dev_register = snd_jack_dev_register, 98 }; 99 100 jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); 101 if (jack == NULL) 102 return -ENOMEM; 103 104 jack->id = kstrdup(id, GFP_KERNEL); 105 106 jack->input_dev = input_allocate_device(); 107 if (jack->input_dev == NULL) { 108 err = -ENOMEM; 109 goto fail_input; 110 } 111 112 jack->input_dev->phys = "ALSA"; 113 114 jack->type = type; 115 116 for (i = 0; i < ARRAY_SIZE(jack_types); i++) 117 if (type & (1 << i)) 118 input_set_capability(jack->input_dev, EV_SW, 119 jack_types[i]); 120 121 err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); 122 if (err < 0) 123 goto fail_input; 124 125 *jjack = jack; 126 127 return 0; 128 129 fail_input: 130 input_free_device(jack->input_dev); 131 kfree(jack); 132 return err; 133 } 134 EXPORT_SYMBOL(snd_jack_new); 135 136 /** 137 * snd_jack_set_parent - Set the parent device for a jack 138 * 139 * @jack: The jack to configure 140 * @parent: The device to set as parent for the jack. 141 * 142 * Set the parent for the jack input device in the device tree. This 143 * function is only valid prior to registration of the jack. If no 144 * parent is configured then the parent device will be the sound card. 145 */ 146 void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) 147 { 148 WARN_ON(jack->registered); 149 150 jack->input_dev->dev.parent = parent; 151 } 152 EXPORT_SYMBOL(snd_jack_set_parent); 153 154 /** 155 * snd_jack_report - Report the current status of a jack 156 * 157 * @jack: The jack to report status for 158 * @status: The current status of the jack 159 */ 160 void snd_jack_report(struct snd_jack *jack, int status) 161 { 162 int i; 163 164 if (!jack) 165 return; 166 167 for (i = 0; i < ARRAY_SIZE(jack_types); i++) { 168 int testbit = 1 << i; 169 if (jack->type & testbit) 170 input_report_switch(jack->input_dev, jack_types[i], 171 status & testbit); 172 } 173 174 input_sync(jack->input_dev); 175 } 176 EXPORT_SYMBOL(snd_jack_report); 177 178 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 179 MODULE_DESCRIPTION("Jack detection support for ALSA"); 180 MODULE_LICENSE("GPL"); 181