/*1* Jack abstraction layer2*3* Copyright 2008 Wolfson Microelectronics4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*19*/2021#include <linux/input.h>22#include <linux/slab.h>23#include <sound/jack.h>24#include <sound/core.h>2526static int jack_switch_types[] = {27SW_HEADPHONE_INSERT,28SW_MICROPHONE_INSERT,29SW_LINEOUT_INSERT,30SW_JACK_PHYSICAL_INSERT,31SW_VIDEOOUT_INSERT,32};3334static int snd_jack_dev_free(struct snd_device *device)35{36struct snd_jack *jack = device->device_data;3738if (jack->private_free)39jack->private_free(jack);4041/* If the input device is registered with the input subsystem42* then we need to use a different deallocator. */43if (jack->registered)44input_unregister_device(jack->input_dev);45else46input_free_device(jack->input_dev);4748kfree(jack->id);49kfree(jack);5051return 0;52}5354static int snd_jack_dev_register(struct snd_device *device)55{56struct snd_jack *jack = device->device_data;57struct snd_card *card = device->card;58int err, i;5960snprintf(jack->name, sizeof(jack->name), "%s %s",61card->shortname, jack->id);62jack->input_dev->name = jack->name;6364/* Default to the sound card device. */65if (!jack->input_dev->dev.parent)66jack->input_dev->dev.parent = snd_card_get_device_link(card);6768/* Add capabilities for any keys that are enabled */69for (i = 0; i < ARRAY_SIZE(jack->key); i++) {70int testbit = SND_JACK_BTN_0 >> i;7172if (!(jack->type & testbit))73continue;7475if (!jack->key[i])76jack->key[i] = BTN_0 + i;7778input_set_capability(jack->input_dev, EV_KEY, jack->key[i]);79}8081err = input_register_device(jack->input_dev);82if (err == 0)83jack->registered = 1;8485return err;86}8788/**89* snd_jack_new - Create a new jack90* @card: the card instance91* @id: an identifying string for this jack92* @type: a bitmask of enum snd_jack_type values that can be detected by93* this jack94* @jjack: Used to provide the allocated jack object to the caller.95*96* Creates a new jack object.97*98* Returns zero if successful, or a negative error code on failure.99* On success jjack will be initialised.100*/101int snd_jack_new(struct snd_card *card, const char *id, int type,102struct snd_jack **jjack)103{104struct snd_jack *jack;105int err;106int i;107static struct snd_device_ops ops = {108.dev_free = snd_jack_dev_free,109.dev_register = snd_jack_dev_register,110};111112jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL);113if (jack == NULL)114return -ENOMEM;115116jack->id = kstrdup(id, GFP_KERNEL);117118jack->input_dev = input_allocate_device();119if (jack->input_dev == NULL) {120err = -ENOMEM;121goto fail_input;122}123124jack->input_dev->phys = "ALSA";125126jack->type = type;127128for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++)129if (type & (1 << i))130input_set_capability(jack->input_dev, EV_SW,131jack_switch_types[i]);132133err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);134if (err < 0)135goto fail_input;136137*jjack = jack;138139return 0;140141fail_input:142input_free_device(jack->input_dev);143kfree(jack->id);144kfree(jack);145return err;146}147EXPORT_SYMBOL(snd_jack_new);148149/**150* snd_jack_set_parent - Set the parent device for a jack151*152* @jack: The jack to configure153* @parent: The device to set as parent for the jack.154*155* Set the parent for the jack input device in the device tree. This156* function is only valid prior to registration of the jack. If no157* parent is configured then the parent device will be the sound card.158*/159void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)160{161WARN_ON(jack->registered);162163jack->input_dev->dev.parent = parent;164}165EXPORT_SYMBOL(snd_jack_set_parent);166167/**168* snd_jack_set_key - Set a key mapping on a jack169*170* @jack: The jack to configure171* @type: Jack report type for this key172* @keytype: Input layer key type to be reported173*174* Map a SND_JACK_BTN_ button type to an input layer key, allowing175* reporting of keys on accessories via the jack abstraction. If no176* mapping is provided but keys are enabled in the jack type then177* BTN_n numeric buttons will be reported.178*179* Note that this is intended to be use by simple devices with small180* numbers of keys that can be reported. It is also possible to181* access the input device directly - devices with complex input182* capabilities on accessories should consider doing this rather than183* using this abstraction.184*185* This function may only be called prior to registration of the jack.186*/187int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,188int keytype)189{190int key = fls(SND_JACK_BTN_0) - fls(type);191192WARN_ON(jack->registered);193194if (!keytype || key >= ARRAY_SIZE(jack->key))195return -EINVAL;196197jack->type |= type;198jack->key[key] = keytype;199200return 0;201}202EXPORT_SYMBOL(snd_jack_set_key);203204/**205* snd_jack_report - Report the current status of a jack206*207* @jack: The jack to report status for208* @status: The current status of the jack209*/210void snd_jack_report(struct snd_jack *jack, int status)211{212int i;213214if (!jack)215return;216217for (i = 0; i < ARRAY_SIZE(jack->key); i++) {218int testbit = SND_JACK_BTN_0 >> i;219220if (jack->type & testbit)221input_report_key(jack->input_dev, jack->key[i],222status & testbit);223}224225for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) {226int testbit = 1 << i;227if (jack->type & testbit)228input_report_switch(jack->input_dev,229jack_switch_types[i],230status & testbit);231}232233input_sync(jack->input_dev);234}235EXPORT_SYMBOL(snd_jack_report);236237MODULE_AUTHOR("Mark Brown <[email protected]>");238MODULE_DESCRIPTION("Jack detection support for ALSA");239MODULE_LICENSE("GPL");240241242