Skip to contentSkip to conversation

Media Device Allocator API

PATCH In review Shuah Khan 2 participants 9 messages Apr 2, 2019

Subsystems (5)
lore
Share & tools
lore

Shuah Khan

author maintainer
#0 lore raw

v15 cover Media Device Allocator API

Media Device Allocator API to allows multiple drivers share a media device. This API solves a very common use-case for media devices where one physical device (an USB stick) provides both audio and video. When such media device exposes a standard USB Audio class, a proprietary Video class, two or more independent drivers will share a single physical USB bridge. In such cases, it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct device as the key. Once the media device is allocated by a driver, other drivers can get a reference to it. The media device is released when all the references are released.

The primary focus for testing The patch series is making sure media device is released when both drivers release the media device with a series of unbind/binds on both drivers.

- both au0828 and snd-usb-aduio as built-in
- both au0828 and snd-usb-aduio as modules
- au0828 as module and snd-usb-aduio as built-in
- au0828 as built-in and snd-usb-aduio as module

Test results can be found at:

https://docs.google.com/document/d/1RMF8Rwj7xHJEoOx6_K2f-REgZJ63BMeAVEf-CV-0HsM/edit?usp=sharing

Changes since v14:
- Fixed typos and Copyright date.
- Made VBI shareable with audio and video.
- Tested with Hans's patch to to fix second VBi stream stepping on active VBI stream. The patch didn't fix the problem.

1. Start qv4l2 -V /dev/vbi0
Start capture - Streaming active

2. Start qv4l2 -V /dev/vbi0
Start capture - Streaming active Streaming won't start and the first stream stops.

There is still a problem in au0828. I am sending the patch series with audio, video, and VBI shareable with this known issue.

Changes since v13:
- Minor changes to variable names and other minor changes to copyright and typos suggested by Hans Verkuil.

Changes since v12:
- Patch 1: Fixed prototype warns from media_dev_allocator.c. Removed dependency on find_module() by adding struct module to input args. Still need module name to pass into media_device API.
- Patch 2 & 4: Update media dev allocator api calls to pass in struct module pointer.
- No changes to Patches 3 & 5.
- Added patch 6 with a test. It can go in separately.

Changes since v11:
- Patch 1: Add CONFIG_MODULES dependency in media_dev_allocator files. to fix compile errors when CONFIG_MODULES is disabled.
- Patch 2, 3: No changes.
- Patch 4: Fix sparse error reported by Dan Carpenter.
- Patch 5: Fix warns found by Hans Verkuil.
- v11 was tested on 5.0-rc7 and addresses comments on v10 series from Hans Verkuil. Fixed problems found in resource sharing logic in au0828 adding a patch 5 to this series. The test plan used for testing resource sharing could serve as a regression test plan and the test results can be found at:
- v10 was tested on 5.0-rc3 and addresses comments on v9 series from Hans Verkuil.

Changes since v10:
- Patch 1: Fixed SPDX tag and removed redundant IS_ENABLED(CONFIG_USB) around media_device_usb_allocate() - Sakari Ailus's review comment.
- Patch 2 and 3: No changes
- Patch 4: Fixed SPDX tag - Sakari Ailus's review comment.
- Carried Reviewed-by tag from Takashi Iwai for the sound from v9.
- Patch 5: This is a new patch added to fix resource sharing inconsistencies and problem found during testing using Han's tests.

Changes since v9:
- Patch 1: Fix mutex assert warning from find_module() calls. This code was written before the change to find_module() that requires callers to hold module_mutex. I missed this during my testing on 4.20-rc6. Hans Verkuil reported the problem.
- Patch 4: sound/usb: Initializes all the entities it can before registering the device based on comments from Hans Verkuil
- Carried Reviewed-by tag from Takashi Iwai for the sound from v9.
- No changes to Patches 2 and 3.

References:
https://lkml.org/lkml/2018/11/2/169
https://www.mail-archive.com/[email protected]/msg105854.html

Shuah Khan (6):
media: Media Device Allocator API
media: change au0828 to use Media Device Allocator API
media: media.h: Enable ALSA MEDIA_INTF_T* interface types sound/usb: Use Media Controller API to share media resources
au0828: fix enable and disable source audio and video inconsistencies
selftests: media_dev_allocator api test

 Documentation/media/kapi/mc-core.rst          |  41 +++
 drivers/media/Makefile                        |   6 +
 drivers/media/media-dev-allocator.c           | 135 ++++++++
 drivers/media/usb/au0828/Kconfig              |   2 +
 drivers/media/usb/au0828/au0828-core.c        | 196 ++++++++---
 drivers/media/usb/au0828/au0828.h             |   6 +-
 include/media/media-dev-allocator.h           |  63 ++++
 include/uapi/linux/media.h                    |  25 +-
 sound/usb/Kconfig                             |   4 +
 sound/usb/Makefile                            |   2 +
 sound/usb/card.c                              |  14 +
 sound/usb/card.h                              |   3 +
 sound/usb/media.c                             | 327 ++++++++++++++++++
 sound/usb/media.h                             |  74 ++++
 sound/usb/mixer.h                             |   3 +
 sound/usb/pcm.c                               |  29 +-
 sound/usb/quirks-table.h                      |   1 +
 sound/usb/stream.c                            |   2 +
 sound/usb/usbaudio.h                          |   6 +
 .../media_tests/media_dev_allocator.sh        |  85 +++++
 20 files changed, 963 insertions(+), 61 deletions(-)
 create mode 100644 drivers/media/media-dev-allocator.c
 create mode 100644 include/media/media-dev-allocator.h
 create mode 100644 sound/usb/media.c
 create mode 100644 sound/usb/media.h
 create mode 100755 tools/testing/selftests/media_tests/media_dev_allocator.sh
Signature · 1 line
2.17.1
author maintainer
#1 lore raw

PATCH v15 1/6 media: Media Device Allocator API

Media Device Allocator API to allows multiple drivers share a media device. This API solves a very common use-case for media devices where one physical device (an USB stick) provides both audio and video. When such media device exposes a standard USB Audio class, a proprietary Video class, two or more independent drivers will share a single physical USB bridge. In such cases, it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct device as the key. Once the media device is allocated by a driver, other drivers can get a reference to it. The media device is released when all the references are released.

---
 Documentation/media/kapi/mc-core.rst |  41 ++++++++
 drivers/media/Makefile               |   6 ++
 drivers/media/media-dev-allocator.c  | 135 +++++++++++++++++++++++++++
 include/media/media-dev-allocator.h  |  63 +++++++++++++
 4 files changed, 245 insertions(+)
 create mode 100644 drivers/media/media-dev-allocator.c
 create mode 100644 include/media/media-dev-allocator.h
Documentation/media/kapi/mc-core.rst +41 -0
index f930725e0d6b..05bba0b61748 100644
@@ -259,6 +259,45 @@ Subsystems should facilitate link validation by providing subsystem specific
 helper functions to provide easy access for commonly needed information, and
 in the end provide a way to use driver-specific callbacks.
 
+Media Controller Device Allocator API
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the media device belongs to more than one driver, the shared media
+device is allocated with the shared struct device as the key for look ups.
+
+The shared media device should stay in registered state until the last
+driver unregisters it. In addition, the media device should be released when
+all the references are released. Each driver gets a reference to the media
+device during probe, when it allocates the media device. If media device is
+already allocated, the allocate API bumps up the refcount and returns the
+existing media device. The driver puts the reference back in its disconnect
+routine when it calls :c:func:`media_device_delete()`.
+
+The media device is unregistered and cleaned up from the kref put handler to
+ensure that the media device stays in registered state until the last driver
+unregisters the media device.
+
+**Driver Usage**
+
+Drivers should use the appropriate media-core routines to manage the shared
+media device life-time handling the two states:
+1. allocate -> register -> delete
+2. get reference to already registered device -> delete
+
+call :c:func:`media_device_delete()` routine to make sure the shared media
+device delete is handled correctly.
+
+**driver probe:**
+Call :c:func:`media_device_usb_allocate()` to allocate or get a reference
+Call :c:func:`media_device_register()`, if media devnode isn't registered
+
+**driver disconnect:**
+Call :c:func:`media_device_delete()` to free the media_device. Freeing is
+handled by the kref put handler.
+
+API Definitions
+^^^^^^^^^^^^^^^
+
 .. kernel-doc:: include/media/media-device.h
 
 .. kernel-doc:: include/media/media-devnode.h
@@ -266,3 +305,5 @@ in the end provide a way to use driver-specific callbacks.
 .. kernel-doc:: include/media/media-entity.h
 
 .. kernel-doc:: include/media/media-request.h
+
+.. kernel-doc:: include/media/media-dev-allocator.h
drivers/media/Makefile +6 -0
index 985d35ec6b29..4a330d0e5e40 100644
@@ -6,6 +6,12 @@
 media-objs	:= media-device.o media-devnode.o media-entity.o \
 		   media-request.o
 
+ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+	ifeq ($(CONFIG_USB),y)
+		media-objs += media-dev-allocator.o
+	endif
+endif
+
 #
 # I2C drivers should come before other drivers, otherwise they'll fail
 # when compiled as builtin drivers
drivers/media/media-dev-allocator.c new file +135 -0

135 lines not on this page · raw message

include/media/media-dev-allocator.h new file +63 -0

63 lines not on this page · raw message

Signature · 1 line
2.17.1
author maintainer
#2 lore raw

PATCH v15 2/6 media: change au0828 to use Media Device Allocator API

In reply to Shuah Khan

Media Device Allocator API to allows multiple drivers share a media device. This API solves a very common use-case for media devices where one physical device (an USB stick) provides both audio and video. When such media device exposes a standard USB Audio class, a proprietary Video class, two or more independent drivers will share a single physical USB bridge. In such cases, it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct device as the key. Once the media device is allocated by a driver, other drivers can get a reference to it. The media device is released when all the references are released.

Change au0828 to use Media Device Allocator API to allocate media device with the parent usb struct device as the key, so it can be shared with the snd_usb_audio driver.

---
 drivers/media/usb/au0828/Kconfig       |  2 ++
 drivers/media/usb/au0828/au0828-core.c | 13 +++++--------
 drivers/media/usb/au0828/au0828.h      |  1 +
 3 files changed, 8 insertions(+), 8 deletions(-)
drivers/media/usb/au0828/Kconfig +2 -0
index 65fc067eb864..98de6e24329e 100644
@@ -2,6 +2,8 @@
 config VIDEO_AU0828
 	tristate "Auvitek AU0828 support"
 	depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
+	select MEDIA_CONTROLLER
+	select MEDIA_CONTROLLER_DVB
 	select I2C_ALGOBIT
 	select VIDEO_TVEEPROM
 	select VIDEOBUF2_VMALLOC if VIDEO_V4L2
drivers/media/usb/au0828/au0828-core.c +5 -8
index 3f8c92a70116..4f8ba6f64d3c 100644
@@ -155,9 +155,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev)
 	dev->media_dev->disable_source = NULL;
 	mutex_unlock(&mdev->graph_mutex);
 
-	media_device_unregister(dev->media_dev);
-	media_device_cleanup(dev->media_dev);
-	kfree(dev->media_dev);
+	media_device_delete(dev->media_dev, KBUILD_MODNAME, THIS_MODULE);
 	dev->media_dev = NULL;
 #endif
 }
@@ -210,14 +208,10 @@ static int au0828_media_device_init(struct au0828_dev *dev,
 #ifdef CONFIG_MEDIA_CONTROLLER
 	struct media_device *mdev;
 
-	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+	mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE);
 	if (!mdev)
 		return -ENOMEM;
 
-	/* check if media device is already initialized */
-	if (!mdev->dev)
-		media_device_usb_init(mdev, udev, udev->product);
-
 	dev->media_dev = mdev;
 #endif
 	return 0;
@@ -480,6 +474,9 @@ static int au0828_media_device_register(struct au0828_dev *dev,
 		/* register media device */
 		ret = media_device_register(dev->media_dev);
 		if (ret) {
+			media_device_delete(dev->media_dev, KBUILD_MODNAME,
+					    THIS_MODULE);
+			dev->media_dev = NULL;
 			dev_err(&udev->dev,
 				"Media Device Register Error: %d\n", ret);
 			return ret;
drivers/media/usb/au0828/au0828.h +1 -0
index 425c35d16057..57b00de8d3f2 100644
@@ -31,6 +31,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
 #include <media/media-device.h>
+#include <media/media-dev-allocator.h>
 
 /* DVB */
 #include <media/demux.h>
Signature · 1 line
2.17.1
author maintainer
#3 lore raw

PATCH v15 3/6 media: media.h: Enable ALSA MEDIA_INTF_T* interface types

In reply to Shuah Khan

Move PCM_CAPTURE, PCM_PLAYBACK, and CONTROL ALSA MEDIA_INTF_T* interface types back into __KERNEL__ scope to get ready for adding ALSA support for these to the media controller.

---
 include/uapi/linux/media.h | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)
include/uapi/linux/media.h +15 -10
index e5d0c5c611b5..9aedb187bc48 100644
@@ -262,6 +262,11 @@ struct media_links_enum {
 #define MEDIA_INTF_T_V4L_SWRADIO		(MEDIA_INTF_T_V4L_BASE + 4)
 #define MEDIA_INTF_T_V4L_TOUCH			(MEDIA_INTF_T_V4L_BASE + 5)
 
+#define MEDIA_INTF_T_ALSA_BASE			0x00000300
+#define MEDIA_INTF_T_ALSA_PCM_CAPTURE		(MEDIA_INTF_T_ALSA_BASE)
+#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK		(MEDIA_INTF_T_ALSA_BASE + 1)
+#define MEDIA_INTF_T_ALSA_CONTROL		(MEDIA_INTF_T_ALSA_BASE + 2)
+
 #if defined(__KERNEL__)
 
 /*
@@ -413,19 +418,19 @@ struct media_v2_topology {
 #define MEDIA_ENT_F_DTV_DECODER			MEDIA_ENT_F_DV_DECODER
 
 /*
- * There is still no ALSA support in the media controller. These
+ * There is still no full ALSA support in the media controller. These
  * defines should not have been added and we leave them here only
  * in case some application tries to use these defines.
+ *
+ * The ALSA defines that are in use have been moved into __KERNEL__
+ * scope. As support gets added to these interface types, they should
+ * be moved into __KERNEL__ scope with the code that uses them.
  */
-#define MEDIA_INTF_T_ALSA_BASE			0x00000300
-#define MEDIA_INTF_T_ALSA_PCM_CAPTURE		(MEDIA_INTF_T_ALSA_BASE)
-#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK		(MEDIA_INTF_T_ALSA_BASE + 1)
-#define MEDIA_INTF_T_ALSA_CONTROL		(MEDIA_INTF_T_ALSA_BASE + 2)
-#define MEDIA_INTF_T_ALSA_COMPRESS		(MEDIA_INTF_T_ALSA_BASE + 3)
-#define MEDIA_INTF_T_ALSA_RAWMIDI		(MEDIA_INTF_T_ALSA_BASE + 4)
-#define MEDIA_INTF_T_ALSA_HWDEP			(MEDIA_INTF_T_ALSA_BASE + 5)
-#define MEDIA_INTF_T_ALSA_SEQUENCER		(MEDIA_INTF_T_ALSA_BASE + 6)
-#define MEDIA_INTF_T_ALSA_TIMER			(MEDIA_INTF_T_ALSA_BASE + 7)
+#define MEDIA_INTF_T_ALSA_COMPRESS             (MEDIA_INTF_T_ALSA_BASE + 3)
+#define MEDIA_INTF_T_ALSA_RAWMIDI              (MEDIA_INTF_T_ALSA_BASE + 4)
+#define MEDIA_INTF_T_ALSA_HWDEP                (MEDIA_INTF_T_ALSA_BASE + 5)
+#define MEDIA_INTF_T_ALSA_SEQUENCER            (MEDIA_INTF_T_ALSA_BASE + 6)
+#define MEDIA_INTF_T_ALSA_TIMER                (MEDIA_INTF_T_ALSA_BASE + 7)
 
 /* Obsolete symbol for media_version, no longer used in the kernel */
 #define MEDIA_API_VERSION			((0 << 16) | (1 << 8) | 0)
Signature · 1 line
2.17.1
author maintainer
#4 lore raw

PATCH v15 4/6 sound/usb: Use Media Controller API to share media resources

In reply to Shuah Khan

Media Device Allocator API to allows multiple drivers share a media device. This API solves a very common use-case for media devices where one physical device (an USB stick) provides both audio and video. When such media device exposes a standard USB Audio class, a proprietary Video class, two or more independent drivers will share a single physical USB bridge. In such cases, it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct device as the key. Once the media device is allocated by a driver, other drivers can get a reference to it. The media device is released when all the references are released.

Change the ALSA driver to use the Media Controller API to share media resources with DVB, and V4L2 drivers on a AU0828 media device.

The Media Controller specific initialization is done after sound card is registered. ALSA creates Media interface and entity function graph nodes for Control, Mixer, PCM Playback, and PCM Capture devices.

snd_usb_hw_params() will call Media Controller enable source handler interface to request the media resource. If resource request is granted, it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is returned.

Media specific cleanup is done in usb_audio_disconnect().

---
 sound/usb/Kconfig        |   4 +
 sound/usb/Makefile       |   2 +
 sound/usb/card.c         |  14 ++
 sound/usb/card.h         |   3 +
 sound/usb/media.c        | 327 +++++++++++++++++++++++++++++++++++++++
 sound/usb/media.h        |  74 +++++++++
 sound/usb/mixer.h        |   3 +
 sound/usb/pcm.c          |  29 +++-
 sound/usb/quirks-table.h |   1 +
 sound/usb/stream.c       |   2 +
 sound/usb/usbaudio.h     |   6 +
 11 files changed, 461 insertions(+), 4 deletions(-)
 create mode 100644 sound/usb/media.c
 create mode 100644 sound/usb/media.h
sound/usb/Kconfig +4 -0
index f61b5662bb89..6319b544ba3a 100644
@@ -15,6 +15,7 @@ config SND_USB_AUDIO
 	select SND_RAWMIDI
 	select SND_PCM
 	select BITREVERSE
+	select SND_USB_AUDIO_USE_MEDIA_CONTROLLER if MEDIA_CONTROLLER && (MEDIA_SUPPORT=y || MEDIA_SUPPORT=SND_USB_AUDIO)
 	help
 	  Say Y here to include support for USB audio and USB MIDI
 	  devices.
@@ -22,6 +23,9 @@ config SND_USB_AUDIO
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-usb-audio.
 
+config SND_USB_AUDIO_USE_MEDIA_CONTROLLER
+	bool
+
 config SND_USB_UA101
 	tristate "Edirol UA-101/UA-1000 driver"
 	select SND_PCM
sound/usb/Makefile +2 -0
index d330f74c90e6..e1ce257ab705 100644
@@ -18,6 +18,8 @@ snd-usb-audio-objs := 	card.o \
 			quirks.o \
 			stream.o
 
+snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o
+
 snd-usbmidi-lib-objs := midi.o
 
 # Toplevel Module Dependency
sound/usb/card.c +14 -0
index 719e10034553..04465d581204 100644
@@ -68,6 +68,7 @@
 #include "format.h"
 #include "power.h"
 #include "stream.h"
+#include "media.h"
 
 MODULE_AUTHOR("Takashi Iwai <[email protected]>");
 MODULE_DESCRIPTION("USB Audio");
@@ -673,6 +674,11 @@ static int usb_audio_probe(struct usb_interface *intf,
 	if (err < 0)
 		goto __error;
 
+	if (quirk && quirk->shares_media_device) {
+		/* don't want to fail when snd_media_device_create() fails */
+		snd_media_device_create(chip, intf);
+	}
+
 	usb_chip[chip->index] = chip;
 	chip->num_interfaces++;
 	usb_set_intfdata(intf, chip);
@@ -732,6 +738,14 @@ static void usb_audio_disconnect(struct usb_interface *intf)
 		list_for_each(p, &chip->midi_list) {
 			snd_usbmidi_disconnect(p);
 		}
+		/*
+		 * Nice to check quirk && quirk->shares_media_device and
+		 * then call the snd_media_device_delete(). Don't have
+		 * access to the quirk here. snd_media_device_delete()
+		 * accesses mixer_list
+		 */
+		snd_media_device_delete(chip);
+
 		/* release mixer resources */
 		list_for_each_entry(mixer, &chip->mixer_list, list) {
 			snd_usb_mixer_disconnect(mixer);
sound/usb/card.h +3 -0
index 79fa2a19fb7b..2991b9986f66 100644
@@ -109,6 +109,8 @@ struct snd_usb_endpoint {
 	struct list_head list;
 };
 
+struct media_ctl;
+
 struct snd_usb_substream {
 	struct snd_usb_stream *stream;
 	struct usb_device *dev;
@@ -161,6 +163,7 @@ struct snd_usb_substream {
 	} dsd_dop;
 
 	bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
+	struct media_ctl *media_ctl;
 };
 
 struct snd_usb_stream {
sound/usb/media.c new file +327 -0

327 lines not on this page · raw message

sound/usb/media.h new file +74 -0

74 lines not on this page · raw message

sound/usb/mixer.h +3 -0
index 3d12af8bf191..394cd9107507 100644
@@ -4,6 +4,8 @@
 
 #include <sound/info.h>
 
+struct media_mixer_ctl;
+
 struct usb_mixer_interface {
 	struct snd_usb_audio *chip;
 	struct usb_host_interface *hostif;
@@ -23,6 +25,7 @@ struct usb_mixer_interface {
 	struct urb *rc_urb;
 	struct usb_ctrlrequest *rc_setup_packet;
 	u8 rc_buffer[6];
+	struct media_mixer_ctl *media_mixer_ctl;
 
 	bool disconnected;
 };
sound/usb/pcm.c +25 -4
index 056af0a57b22..5d8494b2a026 100644
@@ -35,6 +35,7 @@
 #include "pcm.h"
 #include "clock.h"
 #include "power.h"
+#include "media.h"
 
 #define SUBSTREAM_FLAG_DATA_EP_STARTED	0
 #define SUBSTREAM_FLAG_SYNC_EP_STARTED	1
@@ -787,6 +788,10 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 	struct audioformat *fmt;
 	int ret;
 
+	ret = snd_media_start_pipeline(subs);
+	if (ret)
+		return ret;
+
 	if (snd_usb_use_vmalloc)
 		ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 						       params_buffer_bytes(hw_params));
@@ -794,7 +799,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 		ret = snd_pcm_lib_malloc_pages(substream,
 					       params_buffer_bytes(hw_params));
 	if (ret < 0)
-		return ret;
+		goto stop_pipeline;
 
 	subs->pcm_format = params_format(hw_params);
 	subs->period_bytes = params_period_bytes(hw_params);
@@ -808,12 +813,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 		dev_dbg(&subs->dev->dev,
 			"cannot set format: format = %#x, rate = %d, channels = %d\n",
 			   subs->pcm_format, subs->cur_rate, subs->channels);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto stop_pipeline;
 	}
 
 	ret = snd_usb_lock_shutdown(subs->stream->chip);
 	if (ret < 0)
-		return ret;
+		goto stop_pipeline;
 
 	ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0);
 	if (ret < 0)
@@ -829,6 +835,12 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 
  unlock:
 	snd_usb_unlock_shutdown(subs->stream->chip);
+	if (ret < 0)
+		goto stop_pipeline;
+	return ret;
+
+ stop_pipeline:
+	snd_media_stop_pipeline(subs);
 	return ret;
 }
 
@@ -841,6 +853,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_usb_substream *subs = substream->runtime->private_data;
 
+	snd_media_stop_pipeline(subs);
 	subs->cur_audiofmt = NULL;
 	subs->cur_rate = 0;
 	subs->period_bytes = 0;
@@ -1313,6 +1326,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream)
 	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_usb_substream *subs = &as->substream[direction];
+	int ret;
 
 	subs->interface = -1;
 	subs->altset_idx = 0;
@@ -1326,7 +1340,13 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream)
 	subs->dsd_dop.channel = 0;
 	subs->dsd_dop.marker = 1;
 
-	return setup_hw_info(runtime, subs);
+	ret = setup_hw_info(runtime, subs);
+	if (ret == 0) {
+		ret = snd_media_stream_init(subs, as->pcm, direction);
+		if (ret)
+			snd_usb_autosuspend(subs->stream->chip);
+	}
+	return ret;
 }
 
 static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
@@ -1337,6 +1357,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
 	int ret;
 
 	stop_endpoints(subs, true);
+	snd_media_stop_pipeline(subs);
 
 	if (!as->chip->keep_iface &&
 	    subs->interface >= 0 &&
sound/usb/quirks-table.h +1 -0
index 86e80916a029..8cbca137ee6f 100644
@@ -2887,6 +2887,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 		.product_name = pname, \
 		.ifnum = QUIRK_ANY_INTERFACE, \
 		.type = QUIRK_AUDIO_ALIGN_TRANSFER, \
+		.shares_media_device = 1, \
 	} \
 }
 
sound/usb/stream.c +2 -0
index d9e3de495c16..9f1623e37fb3 100644
@@ -38,6 +38,7 @@
 #include "clock.h"
 #include "stream.h"
 #include "power.h"
+#include "media.h"
 
 /*
  * free a substream
@@ -55,6 +56,7 @@ static void free_substream(struct snd_usb_substream *subs)
 	}
 	kfree(subs->rate_list.list);
 	kfree(subs->str_pd);
+	snd_media_stream_delete(subs);
 }
 
 
sound/usb/usbaudio.h +6 -0
index b9faeca645fd..0968a45c8925 100644
@@ -30,6 +30,9 @@
  *
  */
 
+struct media_device;
+struct media_intf_devnode;
+
 struct snd_usb_audio {
 	int index;
 	struct usb_device *dev;
@@ -66,6 +69,8 @@ struct snd_usb_audio {
 					 */
 
 	struct usb_host_interface *ctrl_intf;	/* the audio control interface */
+	struct media_device *media_dev;
+	struct media_intf_devnode *ctl_intf_media_devnode;
 };
 
 #define usb_audio_err(chip, fmt, args...) \
@@ -117,6 +122,7 @@ struct snd_usb_audio_quirk {
 	const char *profile_name;	/* override the card->longname */
 	int16_t ifnum;
 	uint16_t type;
+	bool shares_media_device;
 	const void *data;
 };
 
Signature · 1 line
2.17.1
author maintainer
#5 lore raw

PATCH v15 5/6 au0828: fix enable and disable source audio and video inconsistencies

In reply to Shuah Khan

Enable and disable source interfaces aren't consistent in enforcing how video and audio share the tuner resource.

Fix these issues to enforce the following rules and allow sharing between audio and video applications.

- When DVB is streaming, audio/video/vbi/s-video/composite should find the resource busy. DVB holds the tuner in exclusive mode.
- When video/VBI is streaming, audio can share the tuner and vice versa.
- v4l2 allows multiple applications to open video device.
- Video applications call enable source multiple times during their run-time. Resource should stay locked until the last application releases it.
- A shared resource should stay in shared state and locked when it is in use by audio and video. More than one video application is allowed to use the tuner as long as video streaming protocol allows such usage. Resource is released when the last video/audio application releases it.
- S-Video and Composite hold the resource in exclusive mode.

---
 drivers/media/usb/au0828/au0828-core.c | 183 ++++++++++++++++++++-----
 drivers/media/usb/au0828/au0828.h      |   5 +-
 2 files changed, 149 insertions(+), 39 deletions(-)
drivers/media/usb/au0828/au0828-core.c +145 -38
index 4f8ba6f64d3c..925a80437822 100644
@@ -272,6 +272,28 @@ static void au0828_media_graph_notify(struct media_entity *new,
 	}
 }
 
+static bool au0828_is_link_shareable(struct media_entity *owner,
+				     struct media_entity *entity)
+{
+	bool shareable = false;
+
+	/* Tuner link can be shared by audio, video, and VBI */
+	switch (owner->function) {
+	case MEDIA_ENT_F_IO_V4L:
+	case MEDIA_ENT_F_AUDIO_CAPTURE:
+	case MEDIA_ENT_F_IO_VBI:
+		if (entity->function == MEDIA_ENT_F_IO_V4L ||
+		    entity->function == MEDIA_ENT_F_AUDIO_CAPTURE ||
+		    entity->function == MEDIA_ENT_F_IO_VBI)
+			shareable = true;
+		break;
+	case MEDIA_ENT_F_DTV_DEMOD:
+	default:
+		break;
+	}
+	return shareable;
+}
+
 /* Callers should hold graph_mutex */
 static int au0828_enable_source(struct media_entity *entity,
 				struct media_pipeline *pipe)
@@ -314,18 +336,20 @@ static int au0828_enable_source(struct media_entity *entity,
 		/*
 		 * Default input is tuner and default input_type
 		 * is AU0828_VMUX_TELEVISION.
-		 * FIXME:
+		 *
 		 * There is a problem when s_input is called to
 		 * change the default input. s_input will try to
 		 * enable_source before attempting to change the
 		 * input on the device, and will end up enabling
 		 * default source which is tuner.
 		 *
-		 * Additional logic is necessary in au0828
-		 * to detect that the input has changed and
-		 * enable the right source.
+		 * Additional logic is necessary in au0828 to detect
+		 * that the input has changed and enable the right
+		 * source. au0828 handles this case in its s_input.
+		 * It will disable the old source and enable the new
+		 * source.
+		 *
 		*/
-
 		if (dev->input_type == AU0828_VMUX_TELEVISION)
 			find_source = dev->tuner;
 		else if (dev->input_type == AU0828_VMUX_SVIDEO ||
@@ -338,27 +362,33 @@ static int au0828_enable_source(struct media_entity *entity,
 		}
 	}
 
-	/* Is an active link between sink and source */
+	/* Is there an active link between sink and source */
 	if (dev->active_link) {
-		/*
-		 * If DVB is using the tuner and calling entity is
-		 * audio/video, the following check will be false,
-		 * since sink is different. Result is Busy.
-		 */
-		if (dev->active_link->sink->entity == sink &&
-		    dev->active_link->source->entity == find_source) {
-			/*
-			 * Either ALSA or Video own tuner. sink is
-			 * the same for both. Prevent Video stepping
-			 * on ALSA when ALSA owns the source.
+		if (dev->active_link_owner == entity) {
+			/* This check is necessary to handle multiple
+			 * enable_source calls from v4l_ioctls during
+			 * the course of video/vbi application run-time.
 			*/
-			if (dev->active_link_owner != entity &&
-			    dev->active_link_owner->function ==
-						MEDIA_ENT_F_AUDIO_CAPTURE) {
-				pr_debug("ALSA has the tuner\n");
-				ret = -EBUSY;
-				goto end;
-			}
+			pr_debug("%s already owns the tuner\n", entity->name);
+			ret = 0;
+			goto end;
+		} else if (au0828_is_link_shareable(dev->active_link_owner,
+			   entity)) {
+			/* Either ALSA or Video own tuner. Sink is the same
+			 * for both. Allow sharing the active link between
+			 * their common source (tuner) and sink (decoder).
+			 * Starting pipeline between sharing entity and sink
+			 * will fail with pipe mismatch, while owner has an
+			 * active pipeline. Switch pipeline ownership from
+			 * user to owner when owner disables the source.
+			 */
+			dev->active_link_shared = true;
+			/* save the user info to use from disable */
+			dev->active_link_user = entity;
+			dev->active_link_user_pipe = pipe;
+			pr_debug("%s owns the tuner %s can share!\n",
+				 dev->active_link_owner->name,
+				 entity->name);
 			ret = 0;
 			goto end;
 		} else {
@@ -385,7 +415,7 @@ static int au0828_enable_source(struct media_entity *entity,
 	source = found_link->source->entity;
 	ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED);
 	if (ret) {
-		pr_err("Activate tuner link %s->%s. Error %d\n",
+		pr_err("Activate link from %s->%s. Error %d\n",
 			source->name, sink->name, ret);
 		goto end;
 	}
@@ -395,25 +425,26 @@ static int au0828_enable_source(struct media_entity *entity,
 		pr_err("Start Pipeline: %s->%s Error %d\n",
 			source->name, entity->name, ret);
 		ret = __media_entity_setup_link(found_link, 0);
-		pr_err("Deactivate link Error %d\n", ret);
+		if (ret)
+			pr_err("Deactivate link Error %d\n", ret);
 		goto end;
 	}
-	/*
-	 * save active link and active link owner to avoid audio
-	 * deactivating video owned link from disable_source and
-	 * vice versa
+
+	/* save link state to allow audio and video share the link
+	 * and not disable the link while the other is using it.
+	 * active_link_owner is used to deactivate the link.
 	*/
 	dev->active_link = found_link;
 	dev->active_link_owner = entity;
 	dev->active_source = source;
 	dev->active_sink = sink;
 
-	pr_debug("Enabled Source: %s->%s->%s Ret %d\n",
+	pr_info("Enabled Source: %s->%s->%s Ret %d\n",
 		 dev->active_source->name, dev->active_sink->name,
 		 dev->active_link_owner->name, ret);
 end:
-	pr_debug("au0828_enable_source() end %s %d %d\n",
-		 entity->name, entity->function, ret);
+	pr_debug("%s end: ent:%s fnc:%d ret %d\n",
+		 __func__, entity->name, entity->function, ret);
 	return ret;
 }
 
@@ -432,21 +463,95 @@ static void au0828_disable_source(struct media_entity *entity)
 	if (!dev->active_link)
 		return;
 
-	/* link is active - stop pipeline from source (tuner) */
+	/* link is active - stop pipeline from source
+	 * (tuner/s-video/Composite) to the entity
+	 * When DVB/s-video/Composite owns tuner, it won't be in
+	 * shared state.
+	 */
 	if (dev->active_link->sink->entity == dev->active_sink &&
 	    dev->active_link->source->entity == dev->active_source) {
 		/*
-		 * prevent video from deactivating link when audio
-		 * has active pipeline
+		 * Prevent video from deactivating link when audio
+		 * has active pipeline and vice versa. In addition
+		 * handle the case when more than one video/vbi
+		 * application is sharing the link.
 		*/
+		bool owner_is_audio = false;
+
+		if (dev->active_link_owner->function ==
+		    MEDIA_ENT_F_AUDIO_CAPTURE)
+			owner_is_audio = true;
+
+		if (dev->active_link_shared) {
+			pr_debug("Shared link owner %s user %s %d\n",
+				 dev->active_link_owner->name,
+				 entity->name, dev->users);
+
+			/* Handle video device users > 1
+			 * When audio owns the shared link with
+			 * more than one video users, avoid
+			 * disabling the source and/or switching
+			 * the owner until the last disable_source
+			 * call from video _close(). Use dev->users to
+			 * determine when to switch/disable.
+			 */
+			if (dev->active_link_owner != entity) {
+				/* video device has users > 1 */
+				if (owner_is_audio && dev->users > 1)
+					return;
+
+				dev->active_link_user = NULL;
+				dev->active_link_user_pipe = NULL;
+				dev->active_link_shared = false;
+				return;
+			}
+
+			/* video owns the link and has users > 1 */
+			if (!owner_is_audio && dev->users > 1)
+				return;
+
+			/* stop pipeline */
+			__media_pipeline_stop(dev->active_link_owner);
+			pr_debug("Pipeline stop for %s\n",
+				dev->active_link_owner->name);
+
+			ret = __media_pipeline_start(
+					dev->active_link_user,
+					dev->active_link_user_pipe);
+			if (ret) {
+				pr_err("Start Pipeline: %s->%s %d\n",
+					dev->active_source->name,
+					dev->active_link_user->name,
+					ret);
+				goto deactivate_link;
+			}
+			/* link user is now the owner */
+			dev->active_link_owner = dev->active_link_user;
+			dev->active_link_user = NULL;
+			dev->active_link_user_pipe = NULL;
+			dev->active_link_shared = false;
+
+			pr_debug("Pipeline started for %s\n",
+				dev->active_link_owner->name);
+			return;
+		} else if (!owner_is_audio && dev->users > 1)
+			/* video/vbi owns the link and has users > 1 */
+			return;
+
 		if (dev->active_link_owner != entity)
 			return;
-		__media_pipeline_stop(entity);
+
+		/* stop pipeline */
+		__media_pipeline_stop(dev->active_link_owner);
+		pr_debug("Pipeline stop for %s\n",
+			dev->active_link_owner->name);
+
+deactivate_link:
 		ret = __media_entity_setup_link(dev->active_link, 0);
 		if (ret)
 			pr_err("Deactivate link Error %d\n", ret);
 
-		pr_debug("Disabled Source: %s->%s->%s Ret %d\n",
+		pr_info("Disabled Source: %s->%s->%s Ret %d\n",
 			 dev->active_source->name, dev->active_sink->name,
 			 dev->active_link_owner->name, ret);
 
@@ -454,6 +559,8 @@ static void au0828_disable_source(struct media_entity *entity)
 		dev->active_link_owner = NULL;
 		dev->active_source = NULL;
 		dev->active_sink = NULL;
+		dev->active_link_shared = false;
+		dev->active_link_user = NULL;
 	}
 }
 #endif
drivers/media/usb/au0828/au0828.h +4 -1
index 57b00de8d3f2..b47ecc9affd8 100644
@@ -284,9 +284,12 @@ struct au0828_dev {
 	struct media_entity_notify entity_notify;
 	struct media_entity *tuner;
 	struct media_link *active_link;
-	struct media_entity *active_link_owner;
 	struct media_entity *active_source;
 	struct media_entity *active_sink;
+	struct media_entity *active_link_owner;
+	struct media_entity *active_link_user;
+	struct media_pipeline *active_link_user_pipe;
+	bool active_link_shared;
 #endif
 };
 
Signature · 1 line
2.17.1
author maintainer
#6 lore raw

PATCH v15 6/6 selftests: media_dev_allocator api test

In reply to Shuah Khan

Add a new test for Media Device Allocator API.

Media Device Allocator API to allows multiple drivers share a media device. This API solves a very common use-case for media devices where one physical device (an USB stick) provides both audio and video. When such media device exposes a standard USB Audio class, a proprietary Video class, two or more independent drivers will share a single physical USB bridge. In such cases, it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct device as the key. Once the media device is allocated by a driver, other drivers can get a reference to it. The media device is released when all the references are released.

This test does a series of unbind/bind tests to make sure media device is released correctly when it is no longer is use and when the last driver releases the reference.

---
 .../media_tests/media_dev_allocator.sh        | 85 +++++++++++++++++++
 1 file changed, 85 insertions(+)
 create mode 100755 tools/testing/selftests/media_tests/media_dev_allocator.sh
tools/testing/selftests/media_tests/media_dev_allocator.sh new file +85 -0
new file mode 100755
index 000000000000..ffe00c59a483
@@ -0,0 +1,85 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Media Device Allocator API test script
+# Copyright (c) 2019 Shuah Khan <[email protected]>
+
+echo "Media Device Allocator testing: unbind and bind"
+echo "media driver $1 audio driver $2"
+
+MDRIVER=/sys/bus/usb/drivers/$1
+cd $MDRIVER
+MDEV=$(ls -d *\-*)
+
+ADRIVER=/sys/bus/usb/drivers/$2
+cd $ADRIVER
+ADEV=$(ls -d *\-*.1)
+
+echo "=================================="
+echo "Test unbind both devices - start"
+echo "Running unbind of $MDEV from $MDRIVER"
+echo $MDEV > $MDRIVER/unbind;
+
+echo "Media device should still be present!"
+ls -l /dev/media*
+
+echo "sound driver is at: $ADRIVER"
+echo "Device is: $ADEV"
+
+echo "Running unbind of $ADEV from $ADRIVER"
+echo $ADEV > $ADRIVER/unbind;
+
+echo "Media device should have been deleted!"
+ls -l /dev/media*
+echo "Test unbind both devices - end"
+
+echo "=================================="
+
+echo "Test bind both devices - start"
+echo "Running bind of $MDEV from $MDRIVER"
+echo $MDEV > $MDRIVER/bind;
+
+echo "Media device should be present!"
+ls -l /dev/media*
+
+echo "Running bind of $ADEV from $ADRIVER"
+echo $ADEV > $ADRIVER/bind;
+
+echo "Media device should be there!"
+ls -l /dev/media*
+
+echo "Test bind both devices - end"
+
+echo "=================================="
+
+echo "Test unbind $MDEV - bind $MDEV - unbind $ADEV - bind $ADEV start"
+
+echo "Running unbind of $MDEV from $MDRIVER"
+echo $MDEV > $MDRIVER/unbind;
+
+echo "Media device should be there!"
+ls -l /dev/media*
+
+sleep 1
+
+echo "Running bind of $MDEV from $MDRIVER"
+echo $MDEV > $MDRIVER/bind;
+
+echo "Media device should be there!"
+ls -l /dev/media*
+
+echo "Running unbind of $ADEV from $ADRIVER"
+echo $ADEV > $ADRIVER/unbind;
+
+echo "Media device should be there!"
+ls -l /dev/media*
+
+sleep 1
+
+echo "Running bind of $ADEV from $ADRIVER"
+echo $ADEV > $ADRIVER/bind;
+
+echo "Media device should be there!"
+ls -l /dev/media*
+
+echo "Test unbind $MDEV - bind $MDEV - unbind $ADEV - bind $ADEV end"
+echo "=================================="
Signature · 1 line
2.17.1
#7 lore raw
In reply to Shuah Khan
Quoted 16 lines · Shuah Khan

Media Device Allocator API to allows multiple drivers share a media device. This API solves a very common use-case for media devices where one physical device (an USB stick) provides both audio and video. When such media device exposes a standard USB Audio class, a proprietary Video class, two or more independent drivers will share a single physical USB bridge. In such cases, it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct device as the key. Once the media device is allocated by a driver, other drivers can get a reference to it. The media device is released when all the references are released.

The primary focus for testing The patch series is making sure media device is released when both drivers release the media device with a series of unbind/binds on both drivers.

Quoted 8 lines

- both au0828 and snd-usb-aduio as built-in
- both au0828 and snd-usb-aduio as modules
- au0828 as module and snd-usb-aduio as built-in
- au0828 as built-in and snd-usb-aduio as module

Test results can be found at:

https://docs.google.com/document/d/1RMF8Rwj7xHJEoOx6_K2f-REgZJ63BMeAVEf-CV-0HsM/edit?usp=sharing

Phew, after posting v2 of my patch "au0828: stop video streaming only when last user stops" everything now works as it should, including the issue with two VBI streams you found.

Should I take the selftest patch or will you take that yourself?

Let me know so I can make the pull request for this. It's been a long journey since the first post on April 9th, 2014: "[RFC PATCH 0/2] managed token devres interfaces".

Almost exactly five years of work!

Regards,

Hans

Quoted 104 lines

Changes since v14:
- Fixed typos and Copyright date.
- Made VBI shareable with audio and video.
- Tested with Hans's patch to to fix second VBi stream stepping on active VBI stream. The patch didn't fix the problem.

1. Start qv4l2 -V /dev/vbi0
Start capture - Streaming active

2. Start qv4l2 -V /dev/vbi0
Start capture - Streaming active Streaming won't start and the first stream stops.

There is still a problem in au0828. I am sending the patch series with audio, video, and VBI shareable with this known issue.

Changes since v13:
- Minor changes to variable names and other minor changes to copyright and typos suggested by Hans Verkuil.

Changes since v12:
- Patch 1: Fixed prototype warns from media_dev_allocator.c. Removed dependency on find_module() by adding struct module to input args. Still need module name to pass into media_device API.
- Patch 2 & 4: Update media dev allocator api calls to pass in struct module pointer.
- No changes to Patches 3 & 5.
- Added patch 6 with a test. It can go in separately.

Changes since v11:
- Patch 1: Add CONFIG_MODULES dependency in media_dev_allocator files. to fix compile errors when CONFIG_MODULES is disabled.
- Patch 2, 3: No changes.
- Patch 4: Fix sparse error reported by Dan Carpenter.
- Patch 5: Fix warns found by Hans Verkuil.
- v11 was tested on 5.0-rc7 and addresses comments on v10 series from Hans Verkuil. Fixed problems found in resource sharing logic in au0828 adding a patch 5 to this series. The test plan used for testing resource sharing could serve as a regression test plan and the test results can be found at:
- v10 was tested on 5.0-rc3 and addresses comments on v9 series from Hans Verkuil.

Changes since v10:
- Patch 1: Fixed SPDX tag and removed redundant IS_ENABLED(CONFIG_USB) around media_device_usb_allocate() - Sakari Ailus's review comment.
- Patch 2 and 3: No changes
- Patch 4: Fixed SPDX tag - Sakari Ailus's review comment.
- Carried Reviewed-by tag from Takashi Iwai for the sound from v9.
- Patch 5: This is a new patch added to fix resource sharing inconsistencies and problem found during testing using Han's tests.

Changes since v9:
- Patch 1: Fix mutex assert warning from find_module() calls. This code was written before the change to find_module() that requires callers to hold module_mutex. I missed this during my testing on 4.20-rc6. Hans Verkuil reported the problem.
- Patch 4: sound/usb: Initializes all the entities it can before registering the device based on comments from Hans Verkuil
- Carried Reviewed-by tag from Takashi Iwai for the sound from v9.
- No changes to Patches 2 and 3.

References:
https://lkml.org/lkml/2018/11/2/169
https://www.mail-archive.com/[email protected]/msg105854.html

Shuah Khan (6):
media: Media Device Allocator API
media: change au0828 to use Media Device Allocator API
media: media.h: Enable ALSA MEDIA_INTF_T* interface types sound/usb: Use Media Controller API to share media resources
au0828: fix enable and disable source audio and video inconsistencies
selftests: media_dev_allocator api test

 Documentation/media/kapi/mc-core.rst          |  41 +++
 drivers/media/Makefile                        |   6 +
 drivers/media/media-dev-allocator.c           | 135 ++++++++
 drivers/media/usb/au0828/Kconfig              |   2 +
 drivers/media/usb/au0828/au0828-core.c        | 196 ++++++++---
 drivers/media/usb/au0828/au0828.h             |   6 +-
 include/media/media-dev-allocator.h           |  63 ++++
 include/uapi/linux/media.h                    |  25 +-
 sound/usb/Kconfig                             |   4 +
 sound/usb/Makefile                            |   2 +
 sound/usb/card.c                              |  14 +
 sound/usb/card.h                              |   3 +
 sound/usb/media.c                             | 327 ++++++++++++++++++
 sound/usb/media.h                             |  74 ++++
 sound/usb/mixer.h                             |   3 +
 sound/usb/pcm.c                               |  29 +-
 sound/usb/quirks-table.h                      |   1 +
 sound/usb/stream.c                            |   2 +
 sound/usb/usbaudio.h                          |   6 +
 .../media_tests/media_dev_allocator.sh        |  85 +++++
 20 files changed, 963 insertions(+), 61 deletions(-)
 create mode 100644 drivers/media/media-dev-allocator.c
 create mode 100644 include/media/media-dev-allocator.h
 create mode 100644 sound/usb/media.c
 create mode 100644 sound/usb/media.h
 create mode 100755 tools/testing/selftests/media_tests/media_dev_allocator.sh
author maintainer
#8 lore raw
Quoted 22 lines · Hans Verkuil
Quoted 21 lines · Shuah Khan

Media Device Allocator API to allows multiple drivers share a media device. This API solves a very common use-case for media devices where one physical device (an USB stick) provides both audio and video. When such media device exposes a standard USB Audio class, a proprietary Video class, two or more independent drivers will share a single physical USB bridge. In such cases, it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct device as the key. Once the media device is allocated by a driver, other drivers can get a reference to it. The media device is released when all the references are released.

The primary focus for testing The patch series is making sure media device is released when both drivers release the media device with a series of unbind/binds on both drivers.

- both au0828 and snd-usb-aduio as built-in
- both au0828 and snd-usb-aduio as modules
- au0828 as module and snd-usb-aduio as built-in
- au0828 as built-in and snd-usb-aduio as module

Quoted 8 lines
Quoted 3 lines

Test results can be found at:

https://docs.google.com/document/d/1RMF8Rwj7xHJEoOx6_K2f-REgZJ63BMeAVEf-CV-0HsM/edit?usp=sharing

Phew, after posting v2 of my patch "au0828: stop video streaming only when last user stops" everything now works as it should, including the issue with two VBI streams you found.

Awesome. Thanks for taking care of this. Looks good. I tested the patch and sent Tested-by for it.

Quoted 1 line

Should I take the selftest patch or will you take that yourself?

Please take this through your pull request. Bundling the test with the feature will help promote use of this test :)

Please pick up the null pointer dereference fix in bind path when unbind happens while bind is in progress.

Quoted 5 lines

Let me know so I can make the pull request for this. It's been a long journey since the first post on April 9th, 2014: "[RFC PATCH 0/2] managed token devres interfaces".

Please send the pull request.

Quoted 2 lines

Almost exactly five years of work!

Amazing. We ended up with a far better solution than the the first patch series ! Thanks to everybody that helped me with reviews and testing.

thanks,
-- Shuah