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