[alsa-devel] [PATCH/RFC 1/2] Add jack reporting API for ALSA
Currently very few systems provide information about jack status to user space, even though many have hardware facilities to do detection. Those systems that do use an input device with the existing SW_HEADPHONE_INSERT switch type to do so, often independently of ALSA.
This patch introduces a standard method for representing jacks to user space into ALSA. It allows drivers to register jacks for a sound card with the input subsystem, binding the input device to the card to help user space associate the input devices with their sound cards. The created input devices are named in the form "card longname jack" where jack is provided by the driver when allocating a jack.
The existing user space API with SW_HEADPHONE_INSERT is preserved.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/core.h | 1 + include/sound/jack.h | 51 +++++++++++++++++++ sound/core/Kconfig | 5 ++ sound/core/Makefile | 2 + sound/core/jack.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 195 insertions(+), 0 deletions(-) create mode 100644 include/sound/jack.h create mode 100644 sound/core/jack.c
diff --git a/include/sound/core.h b/include/sound/core.h index ee2d7e1..8c87713 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -53,6 +53,7 @@ typedef int __bitwise snd_device_type_t; #define SNDRV_DEV_INFO ((__force snd_device_type_t) 0x1006) #define SNDRV_DEV_BUS ((__force snd_device_type_t) 0x1007) #define SNDRV_DEV_CODEC ((__force snd_device_type_t) 0x1008) +#define SNDRV_DEV_JACK ((__force snd_device_type_t) 0x1009) #define SNDRV_DEV_LOWLEVEL ((__force snd_device_type_t) 0x2000)
typedef int __bitwise snd_device_state_t; diff --git a/include/sound/jack.h b/include/sound/jack.h new file mode 100644 index 0000000..e5ac26c --- /dev/null +++ b/include/sound/jack.h @@ -0,0 +1,51 @@ +#ifndef __SOUND_JACK_H +#define __SOUND_JACK_H + +/* + * Jack abstraction layer + * + * Copyright 2008 Wolfson Microelectronics plc + * + * + * 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 <sound/core.h> + +struct input_dev; + +/** + * Jack types which can be reported. These values are used as a + * bitmask. + */ +enum snd_jack_types { + SND_JACK_HEADPHONE = 0x0001, +}; + +struct snd_jack { + struct input_dev *input_dev; + int registered; + int type; + const char *id; + char name[100]; +}; + +int snd_jack_new(struct snd_card *card, const char *id, int type, + struct snd_jack **jack); + +void snd_jack_report(struct snd_jack *jack, int status); + +#endif diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 829ca38..4e8e52d 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -16,6 +16,11 @@ config SND_RAWMIDI tristate depends on SND
+config SND_JACK + tristate + depends on SND + depends on INPUT + config SND_SEQUENCER tristate "Sequencer support" depends on SND diff --git a/sound/core/Makefile b/sound/core/Makefile index 5a01c76..e1cb6d6 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -20,9 +20,11 @@ snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o snd-rtctimer-objs := rtctimer.o snd-hwdep-objs := hwdep.o +snd-jack-objs := jack.o
obj-$(CONFIG_SND) += snd.o obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o +obj-$(CONFIG_SND_JACK) += snd-jack.o obj-$(CONFIG_SND_TIMER) += snd-timer.o obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o diff --git a/sound/core/jack.c b/sound/core/jack.c new file mode 100644 index 0000000..1a52997 --- /dev/null +++ b/sound/core/jack.c @@ -0,0 +1,136 @@ +/* + * 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; + + 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->input_dev->dev.parent = card->dev; + + jack->type = type; + + if (type & SND_JACK_HEADPHONE) + input_set_capability(jack->input_dev, EV_SW, + SW_HEADPHONE_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_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); + + 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");
Add a new switch type to the input API for reporting microphone insertion and extend the ALSA jack reporting API to include this. Since a headset is a combination of a microphone and at least a mono headphone a convenience defintion is provided for describing them.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/linux/input.h | 1 + include/sound/jack.h | 4 +++- sound/core/jack.c | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/include/linux/input.h b/include/linux/input.h index d8521c7..07593f2 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -612,6 +612,7 @@ struct input_absinfo { #define SW_TABLET_MODE 0x01 /* set = tablet mode */ #define SW_HEADPHONE_INSERT 0x02 /* set = inserted */ #define SW_RADIO 0x03 /* set = radio enabled */ +#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_MAX 0x0f
/* diff --git a/include/sound/jack.h b/include/sound/jack.h index e5ac26c..1e080c2 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -32,7 +32,9 @@ struct input_dev; * bitmask. */ enum snd_jack_types { - SND_JACK_HEADPHONE = 0x0001, + SND_JACK_HEADPHONE = 0x0001, + SND_JACK_MICROPHONE = 0x0002, + SND_JACK_HEADSET = 0x0003, /* Both microphone and headphone */ };
struct snd_jack { diff --git a/sound/core/jack.c b/sound/core/jack.c index 1a52997..f030be9 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -99,6 +99,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int 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) @@ -126,6 +129,9 @@ 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); }
At Thu, 29 May 2008 22:09:04 +0100, Mark Brown wrote:
Currently very few systems provide information about jack status to user space, even though many have hardware facilities to do detection. Those systems that do use an input device with the existing SW_HEADPHONE_INSERT switch type to do so, often independently of ALSA.
This patch introduces a standard method for representing jacks to user space into ALSA. It allows drivers to register jacks for a sound card with the input subsystem, binding the input device to the card to help user space associate the input devices with their sound cards. The created input devices are named in the form "card longname jack" where jack is provided by the driver when allocating a jack.
The existing user space API with SW_HEADPHONE_INSERT is preserved.
The implementation looks good, simple enough.
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 829ca38..4e8e52d 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -16,6 +16,11 @@ config SND_RAWMIDI tristate depends on SND
+config SND_JACK
- tristate
- depends on SND
- depends on INPUT
If you suppose to "select" SND_JACK, depends have no meaning.
diff --git a/sound/core/Makefile b/sound/core/Makefile index 5a01c76..e1cb6d6 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -20,9 +20,11 @@ snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o snd-rtctimer-objs := rtctimer.o snd-hwdep-objs := hwdep.o +snd-jack-objs := jack.o
obj-$(CONFIG_SND) += snd.o obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o +obj-$(CONFIG_SND_JACK) += snd-jack.o
The code is small, and I don't see a big merit to make it a module.
+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);
The longname field could be sometimes really too long and verbose. I guess shortname would match better.
+int snd_jack_new(struct snd_card *card, const char *id, int type,
struct snd_jack **jjack)
(snip)
- jack->input_dev->phys = "ALSA";
- jack->input_dev->dev.parent = card->dev;
The card->dev pointer might not be initialized always at this stage. You should check rather at register.
Also, someone may want to pass a different device pointer for this. Passing struct device * to snd_jack_new would be an alternative.
thanks,
Takashi
On Fri, May 30, 2008 at 10:15:43AM +0200, Takashi Iwai wrote:
The implementation looks good, simple enough.
Thanks.
Mark Brown wrote:
+config SND_JACK
- tristate
- depends on SND
- depends on INPUT
The code is small, and I don't see a big merit to make it a module.
I agree - I had meant to flag this up, actually. I hadn't been sure if some of the other objects were being built conditionally for size or not since they seemed relatively small too. When I respin I'll remove this option.
- snprintf(jack->name, sizeof(jack->name), "%s %s",
card->longname, jack->id);
The longname field could be sometimes really too long and verbose. I guess shortname would match better.
The general style for input device names tends towards the long and verbose. For example, on my work laptop I have devices with names like:
Macintosh mouse button emulation AT Translated Set 2 Keyboard Lid Switch Power Button (CM) Sleep Button (CM) AlpsPS/2 ALPS GlidePoint
The ALSA long name seems more idiomatic for this context.
+int snd_jack_new(struct snd_card *card, const char *id, int type,
struct snd_jack **jjack)
(snip)
- jack->input_dev->phys = "ALSA";
- jack->input_dev->dev.parent = card->dev;
The card->dev pointer might not be initialized always at this stage. You should check rather at register.
Will do.
Also, someone may want to pass a different device pointer for this. Passing struct device * to snd_jack_new would be an alternative.
Good idea, that might be useful for ASoC v2 sound cards. I'll add something which allows the caller to optionally specify a parent, defaulting to the sound card if none is given.
The only issue might be for user space figuring out which sound card corresponds to which jack but if jacks might be implemented outside of ALSA anyway (which is possible) that could happen anyway.
The following couple of patches update the jack reporting API I posted last week with the feedback I have received so far. The changes since the last submision are:
- Addition of snd_jack_set_parent(), allowing drivers to override the default parent for the input device prior to registration. - The jack detection support is now included unconditionally in ALSA, requiring a dependency on the input subsystem.
I'm not entirely happy with making ALSA depend on input but given that it is only optional on embedded systems and that the input core is not that large it seemed the best way of ensuring that the input subsystem is available for the jack API without hassle for drivers using it, especially given the lack of dependency propagation from select.
Currently very few systems provide information about jack status to user space, even though many have hardware facilities to do detection. Those systems that do use an input device with the existing SW_HEADPHONE_INSERT switch type to do so, often independently of ALSA.
This patch introduces a standard method for representing jacks to user space into ALSA. It allows drivers to register jacks for a sound card with the input subsystem, binding the input device to the card to help user space associate the input devices with their sound cards. The created input devices are named in the form "card longname jack" where jack is provided by the driver when allocating a jack. By default the parent for the input device is the sound card but this can be overridden by the card driver.
The existing user space API with SW_HEADPHONE_INSERT is preserved.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/core.h | 1 + include/sound/jack.h | 52 +++++++++++++++++ sound/Kconfig | 1 + sound/core/Makefile | 3 +- sound/core/jack.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 213 insertions(+), 1 deletions(-) create mode 100644 include/sound/jack.h create mode 100644 sound/core/jack.c
diff --git a/include/sound/core.h b/include/sound/core.h index 695ee53..67543c5 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -63,6 +63,7 @@ typedef int __bitwise snd_device_type_t; #define SNDRV_DEV_INFO ((__force snd_device_type_t) 0x1006) #define SNDRV_DEV_BUS ((__force snd_device_type_t) 0x1007) #define SNDRV_DEV_CODEC ((__force snd_device_type_t) 0x1008) +#define SNDRV_DEV_JACK ((__force snd_device_type_t) 0x1009) #define SNDRV_DEV_LOWLEVEL ((__force snd_device_type_t) 0x2000)
typedef int __bitwise snd_device_state_t; diff --git a/include/sound/jack.h b/include/sound/jack.h new file mode 100644 index 0000000..5cb610d --- /dev/null +++ b/include/sound/jack.h @@ -0,0 +1,52 @@ +#ifndef __SOUND_JACK_H +#define __SOUND_JACK_H + +/* + * Jack abstraction layer + * + * Copyright 2008 Wolfson Microelectronics plc + * + * + * 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 <sound/core.h> + +struct input_dev; + +/** + * Jack types which can be reported. These values are used as a + * bitmask. + */ +enum snd_jack_types { + SND_JACK_HEADPHONE = 0x0001, +}; + +struct snd_jack { + struct input_dev *input_dev; + int registered; + int type; + const char *id; + char name[100]; +}; + +int snd_jack_new(struct snd_card *card, const char *id, int type, + struct snd_jack **jack); +void snd_jack_set_parent(struct snd_jack *jack, struct device *parent); + +void snd_jack_report(struct snd_jack *jack, int status); + +#endif diff --git a/sound/Kconfig b/sound/Kconfig index 4247406..6564c03 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -38,6 +38,7 @@ menu "Advanced Linux Sound Architecture" config SND tristate "Advanced Linux Sound Architecture" depends on SOUND + depends on INPUT help Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), the new base sound system. diff --git a/sound/core/Makefile b/sound/core/Makefile index da8e685..6a7f416 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -3,7 +3,8 @@ # Copyright (c) 1999,2001 by Jaroslav Kysela perex@perex.cz #
-snd-y := sound.o init.o memory.o info.o control.o misc.o device.o +snd-y := sound.o init.o memory.o info.o control.o misc.o device.o \ + jack.o snd-$(CONFIG_ISA_DMA_API) += isadma.o snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o snd-$(CONFIG_SND_VMASTER) += vmaster.o diff --git a/sound/core/jack.c b/sound/core/jack.c new file mode 100644 index 0000000..36ecc57 --- /dev/null +++ b/sound/core/jack.c @@ -0,0 +1,157 @@ +/* + * 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); + + 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) +{ + BUG_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); + + 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");
Add a new switch type to the input API for reporting microphone insertion and extend the ALSA jack reporting API to include this. Since a headset is a combination of a microphone and at least a mono headphone a convenience defintion is provided for describing them.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/linux/input.h | 1 + include/sound/jack.h | 4 +++- sound/core/jack.c | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/include/linux/input.h b/include/linux/input.h index e075c4b..462e891 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -640,6 +640,7 @@ struct input_absinfo { #define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" set = radio enabled */ #define SW_RADIO SW_RFKILL_ALL /* deprecated */ +#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1)
diff --git a/include/sound/jack.h b/include/sound/jack.h index 5cb610d..743f559 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -32,7 +32,9 @@ struct input_dev; * bitmask. */ enum snd_jack_types { - SND_JACK_HEADPHONE = 0x0001, + SND_JACK_HEADPHONE = 0x0001, + SND_JACK_MICROPHONE = 0x0002, + SND_JACK_HEADSET = 0x0003, /* Both microphone and headphone */ };
struct snd_jack { diff --git a/sound/core/jack.c b/sound/core/jack.c index 36ecc57..9c05ec8 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -102,6 +102,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int 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) @@ -147,6 +150,9 @@ 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); }
At Tue, 3 Jun 2008 11:40:48 +0100, Mark Brown wrote:
The following couple of patches update the jack reporting API I posted last week with the feedback I have received so far. The changes since the last submision are:
- Addition of snd_jack_set_parent(), allowing drivers to override the default parent for the input device prior to registration.
- The jack detection support is now included unconditionally in ALSA, requiring a dependency on the input subsystem.
I'm not entirely happy with making ALSA depend on input but given that it is only optional on embedded systems and that the input core is not that large it seemed the best way of ensuring that the input subsystem is available for the jack API without hassle for drivers using it, especially given the lack of dependency propagation from select.
I also feel uneasy that it's built in unconditionally and requires an additional dependency on CONFIG_INPUT. The fact that both SND and INPUT can be modules makes things a bit complicated.
As a workaround, how about to select with "if" conditions? For example, in sound/core/Kconfig,
config SND_JACK bool
while the driver requires SND_JACK has the below:
config SND_FOO tristate "..." ... select SND_JACK if INPUT=y || INPUT=SND
Yeah, it looks horrible at a first glance, but it's a known workaround for reverse selections...
In sound/core/Makefile, just add the line:
snd-$(CONFIG_SND_JACK) += jack.o
so that the code is built into snd module only when necessary.
Also, sound/jack.h should provide empty inline functions for the case CONFIG_SND_JACK=n. Then you'll be able to reduce ifdefs in the driver codes.
thanks,
Takashi
On Tue, Jun 03, 2008 at 04:49:38PM +0200, Takashi Iwai wrote:
Yeah, it looks horrible at a first glance, but it's a known workaround for reverse selections...
Indeed - that was the main other solution I'd looked at. It seemed like too much splatter in the configuration for the drivers but it's about as good as it looks like it'll get if simply depending on input isn't going to be OK.
Looking at all this I'm thinking we may as well leave the jack stuff as a module - it'd at least make the dependency stuff at runtime slightly easier and if we're going to put in the effort to support all these mixes of SND and INPUT it's probably as well to remove the runtime dependency between ALSA and input if jacks aren't actually in use too.
Also, sound/jack.h should provide empty inline functions for the case CONFIG_SND_JACK=n. Then you'll be able to reduce ifdefs in the driver codes.
Yeah, probably. Though from that point of view it might be as well to cut out the SND_JACK middleman...
Hi Mark,
On Tue, Jun 03, 2008 at 11:40:48AM +0100, Mark Brown wrote:
The following couple of patches update the jack reporting API I posted last week with the feedback I have received so far. The changes since the last submision are:
- Addition of snd_jack_set_parent(), allowing drivers to override the default parent for the input device prior to registration.
- The jack detection support is now included unconditionally in ALSA, requiring a dependency on the input subsystem.
I'm not entirely happy with making ALSA depend on input but given that it is only optional on embedded systems and that the input core is not that large it seemed the best way of ensuring that the input subsystem is available for the jack API without hassle for drivers using it, especially given the lack of dependency propagation from select.
I think it is a great idea to intoroduce a mechanism treporting state of a generic connector, it was a long overdue. However I don't think that using input as a delivery mechanism is the best solution. What is needed from a connector:
1. A way to query its state 2. A way to notify userspace of state change.
Pros for using input devices: - we already have them
Cons: - space consideration. Input_dev structure is quite fat. It has all the capabilities strings exported through sysfs, hist of other attributes, etc. On top of that we have a character device (evdev) plus its own sysfs representation. IOW lots of stuff. - input device require ioctl to get the switch state, no easy way to do it through sysfs. - As the number of types of connectors grows new switches will need to be added to input, potentially completely unrelated. My lacmus test for it - does it make sense to add network cable state to inputi core?
Do you think that something small that has only one sysfs device per switch and uses KOBJ_ONLINE/KOBJ_OFFLINE to signal state change would be better suited here?
BTW, the same goes for the SW_DOCK that Matthew wants to add (CC-ed).
On Tue, Jun 03, 2008 at 11:17:26AM -0400, Dmitry Torokhov wrote:
Pros for using input devices:
- we already have them
...and it already models switches.
As mentioned in the description of the original patch there's also the fact that the existing implementations I've found are doing things this way. The only in-kernel ones are corgi and spitz which skip the input device overhead by using the keyboard input device.
There is an additional motivation for using an input device for jacks - it is common to support a button implemented by shorting the microphone connection as well as simply detecting the presence of something in the jack.
Cons:
- space consideration. Input_dev structure is quite fat. It has all the capabilities strings exported through sysfs, hist of other attributes, etc. On top of that we have a character device (evdev) plus its own sysfs representation. IOW lots of stuff.
I'm not sure how many systems this is a concern for these days (the things I found exporting to user space at the minute are embedded) but it could be an issue.
- input device require ioctl to get the switch state, no easy way to do it through sysfs.
That sounds like something that is worth adding anyway, regardless of what gets done with jacks.
- As the number of types of connectors grows new switches will need to be added to input, potentially completely unrelated. My lacmus test for it - does it make sense to add network cable state to inputi core?
The number of potential switches could get rather large, yes - to my mind it's the main concern with using the input API.
Do you think that something small that has only one sysfs device per switch and uses KOBJ_ONLINE/KOBJ_OFFLINE to signal state change would be better suited here?
It's certainly doable and it would avoid any issues with memory overhead and with the number of switch types.
Jacks would in general have more than one thing to report - as well as jacks for headsets with both headphone and optional microphone support on one physical jack many devices will also be able to give an idea of the device connected to a jack, doing things like distinguishing between speakers and headphones. This information could still be exported via the sort of interface you suggest, for example with one sysfs file per thing that can be detected contents indicating the state for that thing. It could also be exported as environment variables along with the uevent. The jack API would be able to standardise the names so that shouldn't be an issue.
Ignoring the buttons it should be fairly straightforward from a kernel point of view. I'm not sure how some of the userspace people would feel about it, mainly those in embedded systems not already dealing with uevents, but if they don't want to use netlink then uevent_helper should do the job for them even though it is a bit more cumbersome than the input API.
Buttons would presumably end up as an input device registered only if supported by the jack - this would be easy enough for the kernel.
If jack reporting is implemented this way we'd want to add a comment indicating that SW_HEADPHONE_INSERT shouldn't be used.
On Wed, Jun 04, 2008 at 12:38:14AM +0100, Mark Brown wrote:
There is an additional motivation for using an input device for jacks - it is common to support a button implemented by shorting the microphone connection as well as simply detecting the presence of something in the jack.
Dimitry, do you have any further thoughts on this? Due to jacks being able to function as buttons as well as switches I do prefer the use of input devices for jack reporting but if you still disagree I'll redo the patch since I don't feel *that* strongly.
On Wed, Jun 04, 2008 at 12:38:14AM +0100, Mark Brown wrote:
There is an additional motivation for using an input device for jacks - it is common to support a button implemented by shorting the microphone connection as well as simply detecting the presence of something in the jack.
Hi Dimitry,
Do you have any further thoughts on this? I'd really like to get this in during 2.6.28 if possible but it really needs your feedback.
Thanks, Mark
participants (3)
-
Dmitry Torokhov
-
Mark Brown
-
Takashi Iwai