Skip to contentSkip to conversation

Add jack reporting API for ALSA

PATCH In review Mark Brown 3 participants 13 messages May 29, 2008 – Jul 1, 2008

Subsystems (3)
lore
Share & tools
lore

Mark Brown

author
#0 lore raw

PATCH 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.

---
 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
include/sound/core.h +1 -0
index ee2d7e1..8c87713 100644
@@ -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;
include/sound/jack.h new file +51 -0

51 lines not on this page · raw message

sound/core/Kconfig +5 -0
index 829ca38..4e8e52d 100644
@@ -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
sound/core/Makefile +2 -0
index 5a01c76..e1cb6d6 100644
@@ -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
sound/core/jack.c new file +136 -0

136 lines not on this page · raw message

Signature · 1 line
1.5.5.1
author
#1 lore raw

PATCH 2/2 Add microphone and headset reporting

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.

---
 include/linux/input.h |    1 +
 include/sound/jack.h  |    4 +++-
 sound/core/jack.c     |    6 ++++++
 3 files changed, 10 insertions(+), 1 deletions(-)
include/linux/input.h +1 -0
index d8521c7..07593f2 100644
@@ -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
 
 /*
include/sound/jack.h +3 -1
index e5ac26c..1e080c2 100644
@@ -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 {
sound/core/jack.c +6 -0
index 1a52997..f030be9 100644
@@ -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);
 }
Signature · 1 line
1.5.5.1
#2 lore raw
In reply to Mark Brown

At Thu, 29 May 2008 22:09:04 +0100,

Quoted 6 lines · Mark Brown

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.

Quoted 8 lines

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.

sound/core/Kconfig config SND_RAWMIDI · line 22

Quoted 12 lines
sound/core/Kconfig +4 -0
index 829ca38..4e8e52d 100644
@@ -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.

sound/core/Makefile snd-rawmidi-objs := rawmidi.o · line 27

Quoted 13 lines
sound/core/Makefile +2 -0
index 5a01c76..e1cb6d6 100644
@@ -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.

sound/core/Makefile snd-rawmidi-objs := rawmidi.o

Quoted 8 lines
sound/core/Makefile +8 -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);

The longname field could be sometimes really too long and verbose. I guess shortname would match better.

Quoted 2 lines
sound/core/Makefile +2 -0
+int snd_jack_new(struct snd_card *card, const char *id, int type,
+		 struct snd_jack **jjack)

(snip)

sound/core/Makefile

Quoted 2 lines
sound/core/Makefile +2 -0
+	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

author
#3 lore raw
Quoted 1 line · Takashi Iwai

The implementation looks good, simple enough.

Thanks.

Quoted 8 lines

sound/core/Kconfig config SND_RAWMIDI · line 22

Quoted 4 lines · Mark Brown
sound/core/Kconfig +4 -0
+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.

Quoted 5 lines

sound/core/jack.c line 49

Quoted 2 lines
sound/core/jack.c new file +2 -0
+	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.

Quoted 8 lines
Quoted 2 lines
sound/core/jack.c new file +2 -0
+int snd_jack_new(struct snd_card *card, const char *id, int type,
+		 struct snd_jack **jjack)

(snip)

sound/core/jack.c line 95

Quoted 2 lines
sound/core/jack.c new file +2 -0
+	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.

Quoted 2 lines

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.

author
#4 lore raw

Jack reporting v2

In reply to Mark Brown

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.

author
#5 lore raw

PATCH 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. 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.

---
 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
include/sound/core.h +1 -0
index 695ee53..67543c5 100644
@@ -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;
include/sound/jack.h new file +52 -0

52 lines not on this page · raw message

sound/Kconfig +1 -0
index 4247406..6564c03 100644
@@ -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.
sound/core/Makefile +2 -1
index da8e685..6a7f416 100644
@@ -3,7 +3,8 @@
 # Copyright (c) 1999,2001 by Jaroslav Kysela <[email protected]>
 #
 
-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
sound/core/jack.c new file +157 -0

157 lines not on this page · raw message

Signature · 1 line
1.5.5.3
author
#6 lore raw

PATCH 2/2 Add microphone and headset reporting

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.

---
 include/linux/input.h |    1 +
 include/sound/jack.h  |    4 +++-
 sound/core/jack.c     |    6 ++++++
 3 files changed, 10 insertions(+), 1 deletions(-)
include/linux/input.h +1 -0
index e075c4b..462e891 100644
@@ -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)
 
include/sound/jack.h +3 -1
index 5cb610d..743f559 100644
@@ -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 {
sound/core/jack.c +6 -0
index 36ecc57..9c05ec8 100644
@@ -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);
 }
Signature · 1 line
1.5.5.3
#7 lore raw

Re: Jack reporting v2

In reply to Mark Brown

At Tue, 3 Jun 2008 11:40:48 +0100,

Quoted 10 lines · Mark Brown

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.

Quoted 5 lines

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

author
#8 lore raw

Re: Jack reporting v2

Quoted 2 lines · Takashi Iwai

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.

Quoted 3 lines

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...

maintainer
#9 lore raw

Re: Jack reporting v2

In reply to Mark Brown

Hi Mark,

Quoted 9 lines · Mark Brown

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.

Quoted 5 lines

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).

Signature · 1 line
Dmitry
author
#10 lore raw

Re: Jack reporting v2

Quoted 2 lines · Dmitry Torokhov

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.

Quoted 5 lines

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.

Quoted 2 lines

- 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.

Quoted 4 lines

- 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.

Quoted 3 lines

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.

author
#11 lore raw

Re: Jack reporting v2

Quoted 4 lines · Mark Brown

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.

author
#12 lore raw

Re: Jack reporting v2

In reply to Mark Brown
Quoted 4 lines · Mark Brown

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