diff options
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/Kconfig | 6 | ||||
-rw-r--r-- | sound/core/Makefile | 1 | ||||
-rw-r--r-- | sound/core/jack.c | 163 | ||||
-rw-r--r-- | sound/core/pcm.c | 50 | ||||
-rw-r--r-- | sound/core/sound.c | 2 |
5 files changed, 207 insertions, 15 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 335d45ecde6a..9c4da1cd4a6b 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -12,6 +12,12 @@ config SND_HWDEP config SND_RAWMIDI tristate +# To be effective this also requires INPUT - users should say: +# select SND_JACK if INPUT=y || INPUT=SND +# to avoid having to force INPUT on. +config SND_JACK + bool + config SND_SEQUENCER tristate "Sequencer support" select SND_TIMER diff --git a/sound/core/Makefile b/sound/core/Makefile index da8e685eef9c..d57125a5687d 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -7,6 +7,7 @@ snd-y := sound.o init.o memory.o info.o control.o misc.o device.o snd-$(CONFIG_ISA_DMA_API) += isadma.o snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o snd-$(CONFIG_SND_VMASTER) += vmaster.o +snd-$(CONFIG_SND_JACK) += jack.o snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o diff --git a/sound/core/jack.c b/sound/core/jack.c new file mode 100644 index 000000000000..8133a2b173a5 --- /dev/null +++ b/sound/core/jack.c @@ -0,0 +1,163 @@ +/* + * Jack abstraction layer + * + * Copyright 2008 Wolfson Microelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/input.h> +#include <sound/jack.h> +#include <sound/core.h> + +static int snd_jack_dev_free(struct snd_device *device) +{ + struct snd_jack *jack = device->device_data; + + /* If the input device is registered with the input subsystem + * then we need to use a different deallocator. */ + if (jack->registered) + input_unregister_device(jack->input_dev); + else + input_free_device(jack->input_dev); + + kfree(jack); + + return 0; +} + +static int snd_jack_dev_register(struct snd_device *device) +{ + struct snd_jack *jack = device->device_data; + struct snd_card *card = device->card; + int err; + + snprintf(jack->name, sizeof(jack->name), "%s %s", + card->longname, jack->id); + jack->input_dev->name = jack->name; + + /* Default to the sound card device. */ + if (!jack->input_dev->dev.parent) + jack->input_dev->dev.parent = card->dev; + + err = input_register_device(jack->input_dev); + if (err == 0) + jack->registered = 1; + + return err; +} + +/** + * snd_jack_new - Create a new jack + * @card: the card instance + * @id: an identifying string for this jack + * @type: a bitmask of enum snd_jack_type values that can be detected by + * this jack + * @jjack: Used to provide the allocated jack object to the caller. + * + * Creates a new jack object. + * + * Returns zero if successful, or a negative error code on failure. + * On success jjack will be initialised. + */ +int snd_jack_new(struct snd_card *card, const char *id, int type, + struct snd_jack **jjack) +{ + struct snd_jack *jack; + int err; + static struct snd_device_ops ops = { + .dev_free = snd_jack_dev_free, + .dev_register = snd_jack_dev_register, + }; + + jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); + if (jack == NULL) + return -ENOMEM; + + jack->id = id; + + jack->input_dev = input_allocate_device(); + if (jack->input_dev == NULL) { + err = -ENOMEM; + goto fail_input; + } + + jack->input_dev->phys = "ALSA"; + + jack->type = type; + + if (type & SND_JACK_HEADPHONE) + input_set_capability(jack->input_dev, EV_SW, + SW_HEADPHONE_INSERT); + if (type & SND_JACK_MICROPHONE) + input_set_capability(jack->input_dev, EV_SW, + SW_MICROPHONE_INSERT); + + err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); + if (err < 0) + goto fail_input; + + *jjack = jack; + + return 0; + +fail_input: + input_free_device(jack->input_dev); + kfree(jack); + return err; +} +EXPORT_SYMBOL(snd_jack_new); + +/** + * snd_jack_set_parent - Set the parent device for a jack + * + * @jack: The jack to configure + * @parent: The device to set as parent for the jack. + * + * Set the parent for the jack input device in the device tree. This + * function is only valid prior to registration of the jack. If no + * parent is configured then the parent device will be the sound card. + */ +void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) +{ + WARN_ON(jack->registered); + + jack->input_dev->dev.parent = parent; +} +EXPORT_SYMBOL(snd_jack_set_parent); + +/** + * snd_jack_report - Report the current status of a jack + * + * @jack: The jack to report status for + * @status: The current status of the jack + */ +void snd_jack_report(struct snd_jack *jack, int status) +{ + if (jack->type & SND_JACK_HEADPHONE) + input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, + status & SND_JACK_HEADPHONE); + if (jack->type & SND_JACK_MICROPHONE) + input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, + status & SND_JACK_MICROPHONE); + + input_sync(jack->input_dev); +} +EXPORT_SYMBOL(snd_jack_report); + +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_DESCRIPTION("Jack detection support for ALSA"); +MODULE_LICENSE("GPL"); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 9dd9bc73fe1d..4c6facb62892 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -42,7 +42,7 @@ static int snd_pcm_dev_free(struct snd_device *device); static int snd_pcm_dev_register(struct snd_device *device); static int snd_pcm_dev_disconnect(struct snd_device *device); -static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) +static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device) { struct snd_pcm *pcm; @@ -53,6 +53,37 @@ static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) return NULL; } +static int snd_pcm_next(struct snd_card *card, int device) +{ + struct snd_pcm *pcm; + + list_for_each_entry(pcm, &snd_pcm_devices, list) { + if (pcm->card == card && pcm->device > device) + return pcm->device; + else if (pcm->card->number > card->number) + return -1; + } + return -1; +} + +static int snd_pcm_add(struct snd_pcm *newpcm) +{ + struct snd_pcm *pcm; + + list_for_each_entry(pcm, &snd_pcm_devices, list) { + if (pcm->card == newpcm->card && pcm->device == newpcm->device) + return -EBUSY; + if (pcm->card->number > newpcm->card->number || + (pcm->card == newpcm->card && + pcm->device > newpcm->device)) { + list_add(&newpcm->list, pcm->list.prev); + return 0; + } + } + list_add_tail(&newpcm->list, &snd_pcm_devices); + return 0; +} + static int snd_pcm_control_ioctl(struct snd_card *card, struct snd_ctl_file *control, unsigned int cmd, unsigned long arg) @@ -65,14 +96,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)arg)) return -EFAULT; mutex_lock(®ister_mutex); - device = device < 0 ? 0 : device + 1; - while (device < SNDRV_PCM_DEVICES) { - if (snd_pcm_search(card, device)) - break; - device++; - } - if (device == SNDRV_PCM_DEVICES) - device = -1; + device = snd_pcm_next(card, device); mutex_unlock(®ister_mutex); if (put_user(device, (int __user *)arg)) return -EFAULT; @@ -98,7 +122,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card, if (get_user(subdevice, &info->subdevice)) return -EFAULT; mutex_lock(®ister_mutex); - pcm = snd_pcm_search(card, device); + pcm = snd_pcm_get(card, device); if (pcm == NULL) { err = -ENXIO; goto _error; @@ -931,11 +955,11 @@ static int snd_pcm_dev_register(struct snd_device *device) snd_assert(pcm != NULL && device != NULL, return -ENXIO); mutex_lock(®ister_mutex); - if (snd_pcm_search(pcm->card, pcm->device)) { + err = snd_pcm_add(pcm); + if (err) { mutex_unlock(®ister_mutex); - return -EBUSY; + return err; } - list_add_tail(&pcm->list, &snd_pcm_devices); for (cidx = 0; cidx < 2; cidx++) { int devtype = -1; if (pcm->streams[cidx].substream == NULL) diff --git a/sound/core/sound.c b/sound/core/sound.c index 1003ae375d47..838dd9ee957c 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -34,8 +34,6 @@ #include <linux/kmod.h> #include <linux/mutex.h> -#define SNDRV_OS_MINORS 256 - static int major = CONFIG_SND_MAJOR; int snd_major; EXPORT_SYMBOL(snd_major); |