linux/sound/core/jack.c
<<
>>
Prefs
   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
  26static 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
  34static 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
  54static 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 */
  88int 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
 128fail_input:
 129        input_free_device(jack->input_dev);
 130        kfree(jack);
 131        return err;
 132}
 133EXPORT_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 */
 145void 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}
 151EXPORT_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 */
 159void 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}
 175EXPORT_SYMBOL(snd_jack_report);
 176
 177MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 178MODULE_DESCRIPTION("Jack detection support for ALSA");
 179MODULE_LICENSE("GPL");
 180