This patch adds support for v4l-audio devices to v4l2-ctl, v4l2-compliance
and the test-media script.

This is RFC quality: when media controller support is added to the m2m audio
drivers, this patch will need to be updated. And it also need to be split into
smaller pieces, but I will wait with that until vim2m-audio uses the media
controller.

Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl>
---
diff --git a/contrib/test/test-media b/contrib/test/test-media
index afe20760..c2a71b89 100755
--- a/contrib/test/test-media
+++ b/contrib/test/test-media
@@ -7,6 +7,7 @@
 vidtv=0
 vivid=0
 vim2m=0
+vim2m_audio=0
 vimc=0
 vicodec=0
 cec=0
@@ -53,13 +54,14 @@ if [ -z "$1" ]; then
        echo Test Targets:
        echo "vivid: test the vivid driver"
        echo "vim2m: test the vim2m driver"
+       echo "vim2m-audio: test the vim2m-audio driver"
        echo "vimc: test the vimc driver"
        echo "vicodec: test the vicodec driver"
        echo "vidtv: test the vidtv driver"
        echo "cec: adds the vivid CEC compliance tests, except for the CEC 
standby/wakeup tests."
        echo "cec-pwr: adds the vivid CEC compliance tests, including the CEC 
standby/wakeup tests."
-       echo "all: equals 'vivid vim2m vimc vicodec vidtv cec cec-pwr'"
-       echo "mc: equals 'vivid vim2m vimc vicodec vidtv'"
+       echo "all: equals 'vivid vim2m vim2m-audio vimc vicodec vidtv cec 
cec-pwr'"
+       echo "mc: equals 'vivid vim2m vim2m-audio vimc vicodec vidtv'"
        exit 0
 fi

@@ -116,6 +118,7 @@ while [ ! -z "$1" ]; do
                vidtv=1
                vivid=1
                vim2m=1
+               vim2m_audio=1
                vimc=1
                vicodec=1
                cec=1
@@ -124,6 +127,7 @@ while [ ! -z "$1" ]; do
        mc)
                vivid=1
                vim2m=1
+               vim2m_audio=1
                vimc=1
                vicodec=1
                vidtv=1
@@ -137,6 +141,9 @@ while [ ! -z "$1" ]; do
        vim2m)
                vim2m=1
                ;;
+       vim2m-audio)
+               vim2m_audio=1
+               ;;
        vimc)
                vimc=1
                ;;
@@ -421,6 +428,83 @@ if [ $vim2m -eq 1 -a $setup -eq 0 ]; then
        echo
 fi

+
+if [ $vim2m_audio -eq 1 ]; then
+       rmmod vim2m-audio 2&>/dev/null
+       modprobe vim2m-audio
+       sleep $modprobe_time
+       dmesg -n notice
+
+       if ! $v4l2_ctl -z platform:vim2m-audio ; then
+               echo "FAIL: the vim2m-audio module failed to load" | tee -a $tmp
+               echo "Grand Total for vim2m-audio: Succeeded: 0, Failed: 1, 
Warnings: 0" | tee -a $tmp
+               echo "Final Summary: 1, Succeeded: 0, Failed: 1, Warnings: 0"
+               rmmod vivid
+               exit 0
+       fi
+fi
+
+if [ $vim2m_audio -eq 1 -a $setup -eq 0 ]; then
+       echo
+       echo vim2m-audio compliance tests | tee /dev/kmsg
+       echo
+       date
+       stdbuf -oL $v4l2_compliance -A0 -z platform:vivid-002 -e 
vivid-002-vid-cap -s10 -P -a 2>&1 | tee -a $tmp
+       echo
+       echo
+       echo
+       echo
+       echo
+       echo
+       echo
+       echo
+       echo
+       echo unbind vim2m-audio | tee /dev/kmsg
+       echo
+       echo -n vim2m-audio.0 >/sys/bus/platform/drivers/vim2m-audio/unbind
+       sleep $unbind_time
+       echo
+       echo rebind vim2m-audio | tee /dev/kmsg
+       echo
+       echo -n vim2m-audio.0 >/sys/bus/platform/drivers/vim2m-audio/bind
+       sleep 1
+       echo
+       echo second unbind vim2m-audio | tee /dev/kmsg
+       echo
+       for i in `$v4l2_ctl -z platform:vim2m-audio --list-devices`; do
+               let "t = 1 + $RANDOM / 4096"
+               echo $i: sleep ${t}s
+               sleep $t <$i &
+       done
+       sleep 1
+       echo
+       echo -n vim2m-audio.0 >/sys/bus/platform/drivers/vim2m-audio/unbind
+       sleep $reunbind_time
+       echo
+       echo rmmod vim2m-audio | tee /dev/kmsg
+       echo
+       rmmod vim2m-audio
+       sleep $rmmod_time
+       if [ $kmemleak -eq 1 ]; then
+               echo
+               echo kmemleak results for vim2m-audio:
+               echo
+               echo scan >/sys/kernel/debug/kmemleak
+               cat /sys/kernel/debug/kmemleak
+               echo
+               echo end of kmemleak results
+               echo clear >/sys/kernel/debug/kmemleak
+       fi
+       echo
+       echo
+       echo
+       echo
+       echo
+       echo
+       echo
+       echo
+fi
+
 if [ $vimc -eq 1 ]; then
        rmmod vimc 2&>/dev/null
        modprobe vimc
diff --git a/utils/common/cv4l-helpers.h b/utils/common/cv4l-helpers.h
index 91a04146..235368ec 100644
--- a/utils/common/cv4l-helpers.h
+++ b/utils/common/cv4l-helpers.h
@@ -78,6 +78,13 @@ public:
        bool has_rds_out() const { return v4l_has_rds_out(this); }
        bool has_sdr_cap() const { return v4l_has_sdr_cap(this); }
        bool has_sdr_out() const { return v4l_has_sdr_out(this); }
+       bool has_touch() const { return v4l_has_touch(this); }
+       bool has_meta_cap() const { return v4l_has_meta_cap(this); }
+       bool has_meta_out() const { return v4l_has_meta_out(this); }
+       bool has_audio_cap() const { return v4l_has_audio_cap(this); }
+       bool has_audio_out() const { return v4l_has_audio_out(this); }
+       bool has_audio_m2m() const { return v4l_has_audio_m2m(this); }
+       bool has_m2m() const { return v4l_has_m2m(this); }
        bool has_hwseek() const { return v4l_has_hwseek(this); }
        bool has_rw() const { return v4l_has_rw(this); }
        bool has_streaming() const { return v4l_has_streaming(this); }
diff --git a/utils/common/v4l-helpers.h b/utils/common/v4l-helpers.h
index 5a256603..a01b3e48 100644
--- a/utils/common/v4l-helpers.h
+++ b/utils/common/v4l-helpers.h
@@ -404,11 +404,26 @@ static inline bool v4l_has_touch(const struct v4l_fd *f)
        return v4l_g_caps(f) & V4L2_CAP_TOUCH;
 }

+static inline bool v4l_has_audio_cap(const struct v4l_fd *f)
+{
+       return v4l_g_caps(f) & V4L2_CAP_AUDIO_M2M;
+}
+
+static inline bool v4l_has_audio_out(const struct v4l_fd *f)
+{
+       return v4l_g_caps(f) & V4L2_CAP_AUDIO_M2M;
+}
+
 static inline bool v4l_has_audio_m2m(const struct v4l_fd *f)
 {
        return v4l_g_caps(f) & V4L2_CAP_AUDIO_M2M;
 }

+static inline bool v4l_has_m2m(const struct v4l_fd *f)
+{
+       return v4l_has_vid_m2m(f) || v4l_has_audio_m2m(f);
+}
+
 static inline bool v4l_has_hwseek(const struct v4l_fd *f)
 {
        return v4l_g_caps(f) & V4L2_CAP_HW_FREQ_SEEK;
@@ -454,6 +469,10 @@ static inline __u32 v4l_determine_type(const struct v4l_fd 
*f)
                return V4L2_BUF_TYPE_META_CAPTURE;
        if (v4l_has_meta_out(f))
                return V4L2_BUF_TYPE_META_OUTPUT;
+       if (v4l_has_audio_cap(f))
+               return V4L2_BUF_TYPE_AUDIO_CAPTURE;
+       if (v4l_has_audio_out(f))
+               return V4L2_BUF_TYPE_AUDIO_OUTPUT;

        return 0;
 }
@@ -706,6 +725,10 @@ static inline void v4l_format_s_pixelformat(struct 
v4l2_format *fmt, __u32 pixel
        case V4L2_BUF_TYPE_META_OUTPUT:
                fmt->fmt.meta.dataformat = pixelformat;
                break;
+       case V4L2_BUF_TYPE_AUDIO_CAPTURE:
+       case V4L2_BUF_TYPE_AUDIO_OUTPUT:
+               fmt->fmt.audio.audioformat = pixelformat;
+               break;
        }
 }

@@ -727,6 +750,9 @@ static inline __u32 v4l_format_g_pixelformat(const struct 
v4l2_format *fmt)
        case V4L2_BUF_TYPE_META_CAPTURE:
        case V4L2_BUF_TYPE_META_OUTPUT:
                return fmt->fmt.meta.dataformat;
+       case V4L2_BUF_TYPE_AUDIO_CAPTURE:
+       case V4L2_BUF_TYPE_AUDIO_OUTPUT:
+               return fmt->fmt.audio.audioformat;
        default:
                return 0;
        }
@@ -1068,6 +1094,9 @@ v4l_format_g_sizeimage(const struct v4l2_format *fmt, 
unsigned plane)
        case V4L2_BUF_TYPE_META_CAPTURE:
        case V4L2_BUF_TYPE_META_OUTPUT:
                return plane ? 0 : fmt->fmt.meta.buffersize;
+       case V4L2_BUF_TYPE_AUDIO_CAPTURE:
+       case V4L2_BUF_TYPE_AUDIO_OUTPUT:
+               return plane ? 0 : fmt->fmt.audio.buffersize;
        default:
                return 0;
        }
@@ -1192,12 +1221,22 @@ static inline bool v4l_type_is_meta(unsigned type)
               type == V4L2_BUF_TYPE_META_OUTPUT;
 }

+static inline bool v4l_type_is_audio(unsigned type)
+{
+       return type == V4L2_BUF_TYPE_AUDIO_CAPTURE ||
+              type == V4L2_BUF_TYPE_AUDIO_OUTPUT;
+}
+
 static inline unsigned v4l_type_invert(unsigned type)
 {
        if (v4l_type_is_planar(type))
                return v4l_type_is_output(type) ?
                        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
                        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       if (v4l_type_is_audio(type))
+               return v4l_type_is_output(type) ?
+                       V4L2_BUF_TYPE_AUDIO_CAPTURE :
+                       V4L2_BUF_TYPE_AUDIO_OUTPUT;
        return v4l_type_is_output(type) ?
                V4L2_BUF_TYPE_VIDEO_CAPTURE :
                V4L2_BUF_TYPE_VIDEO_OUTPUT;
diff --git a/utils/v4l2-compliance/v4l2-compliance.h 
b/utils/v4l2-compliance/v4l2-compliance.h
index bba56b12..1e83fba3 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -102,7 +102,7 @@ using frmsizes_count_map = std::map<__u32, unsigned>;

 struct base_node;

-#define V4L2_BUF_TYPE_LAST V4L2_BUF_TYPE_META_OUTPUT
+#define V4L2_BUF_TYPE_LAST V4L2_BUF_TYPE_AUDIO_OUTPUT

 struct base_node {
        bool is_video;
diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp 
b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index 6d592c9b..d5c8d17c 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -235,12 +235,14 @@ public:
                if (v4l_type_is_output(g_type()))
                        fill_output_buf(fill_bytesused);
                err = node->qbuf(*this);
-               if (err == 0 &&
-                   v4l_type_is_video(g_type()) && 
v4l_type_is_output(g_type())) {
-                       fail_on_test(g_field() == V4L2_FIELD_ANY);
+               if (err)
+                       return err;
+               if (v4l_type_is_output(g_type())) {
+                       if (v4l_type_is_video(g_type()))
+                               fail_on_test(g_field() == V4L2_FIELD_ANY);
                        buffer_info[g_timestamp()] = buf;
                }
-               return err;
+               return 0;
        }
        int qbuf(node *node, const cv4l_queue &q)
        {
diff --git a/utils/v4l2-compliance/v4l2-test-formats.cpp 
b/utils/v4l2-compliance/v4l2-test-formats.cpp
index c92e9658..adec678a 100644
--- a/utils/v4l2-compliance/v4l2-test-formats.cpp
+++ b/utils/v4l2-compliance/v4l2-test-formats.cpp
@@ -451,6 +451,7 @@ static int testFormatsType(struct node *node, int ret,  
unsigned type, struct v4
        struct v4l2_sliced_vbi_format &sliced = fmt.fmt.sliced;
        struct v4l2_sdr_format &sdr = fmt.fmt.sdr;
        struct v4l2_meta_format &meta = fmt.fmt.meta;
+       struct v4l2_audio_format &audio = fmt.fmt.audio;
        unsigned min_data_samples;
        unsigned min_sampling_rate;
        v4l2_std_id std;
@@ -595,6 +596,13 @@ static int testFormatsType(struct node *node, int ret,  
unsigned type, struct v4
                                        meta.dataformat, 
fcc2s(meta.dataformat).c_str(), type);
                fail_on_test(meta.buffersize == 0);
                break;
+       case V4L2_BUF_TYPE_AUDIO_CAPTURE:
+       case V4L2_BUF_TYPE_AUDIO_OUTPUT:
+               if (map.find(audio.audioformat) == map.end())
+                       return fail("audioformat %08x (%s) for buftype %d not 
reported by ENUM_FMT\n",
+                                       audio.audioformat, 
fcc2s(audio.audioformat).c_str(), type);
+               fail_on_test(audio.buffersize == 0);
+               break;
        case V4L2_BUF_TYPE_PRIVATE:
                break;
        }
@@ -709,6 +717,9 @@ static bool matchFormats(const struct v4l2_format &f1, 
const struct v4l2_format
        case V4L2_BUF_TYPE_META_CAPTURE:
        case V4L2_BUF_TYPE_META_OUTPUT:
                return !memcmp(&f1.fmt.meta, &f2.fmt.meta, sizeof(f1.fmt.meta));
+       case V4L2_BUF_TYPE_AUDIO_CAPTURE:
+       case V4L2_BUF_TYPE_AUDIO_OUTPUT:
+               return !memcmp(&f1.fmt.audio, &f2.fmt.audio, 
sizeof(f1.fmt.audio));

        }
        return false;
@@ -788,6 +799,10 @@ int testTryFormats(struct node *node)
                        case V4L2_BUF_TYPE_META_OUTPUT:
                                pixelformat = fmt.fmt.meta.dataformat;
                                break;
+                       case V4L2_BUF_TYPE_AUDIO_CAPTURE:
+                       case V4L2_BUF_TYPE_AUDIO_OUTPUT:
+                               pixelformat = fmt.fmt.audio.audioformat;
+                               break;
                        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
                        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
                                pixelformat = fmt.fmt.pix_mp.pixelformat;
@@ -866,6 +881,9 @@ static int testM2MFormats(struct node *node)
        fail_on_test(node->g_fmt(fmt_out, out_type));
        fail_on_test(node->g_fmt(fmt_cap, cap_type));

+       if (node->has_audio_m2m())
+               return 0;
+
        /*
         * JPEG codec have fixed colorspace, so these tests
         * are different compared to other m2m devices.
@@ -1138,6 +1156,10 @@ int testSetFormats(struct node *node)
                        case V4L2_BUF_TYPE_META_OUTPUT:
                                pixelformat = fmt_set.fmt.meta.dataformat;
                                break;
+                       case V4L2_BUF_TYPE_AUDIO_CAPTURE:
+                       case V4L2_BUF_TYPE_AUDIO_OUTPUT:
+                               pixelformat = fmt_set.fmt.audio.audioformat;
+                               break;
                        case V4L2_BUF_TYPE_SDR_CAPTURE:
                        case V4L2_BUF_TYPE_SDR_OUTPUT:
                                pixelformat = fmt_set.fmt.sdr.pixelformat;
diff --git a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp 
b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
index ffa36164..18dd2c9b 100644
--- a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
@@ -2156,7 +2156,7 @@ static FILE *open_input_file(cv4l_fd &fd, __u32 type)

 static void streaming_set_out(cv4l_fd &fd, cv4l_fd &exp_fd)
 {
-       __u32 type = fd.has_vid_m2m() ? v4l_type_invert(fd.g_type()) : 
fd.g_type();
+       __u32 type = fd.has_m2m() ? v4l_type_invert(fd.g_type()) : fd.g_type();
        cv4l_queue q(type, out_memory);
        cv4l_queue exp_q(exp_fd.g_type(), V4L2_MEMORY_MMAP);
        int fd_flags = fcntl(fd.g_fd(), F_GETFL);
@@ -2713,7 +2713,7 @@ static void streaming_set_m2m(cv4l_fd &fd, cv4l_fd 
&exp_fd)
        fd.g_fmt(fmt[OUT], out.g_type());
        fd.g_fmt(fmt[CAP], in.g_type());

-       if (!fd.has_vid_m2m()) {
+       if (!fd.has_m2m()) {
                fprintf(stderr, "unsupported m2m stream type\n");
                return;
        }
@@ -2763,7 +2763,7 @@ static void streaming_set_cap2out(cv4l_fd &fd, cv4l_fd 
&out_fd)
        bool use_poll = options[OptStreamPoll];
        bool use_dmabuf = options[OptStreamDmaBuf] || 
options[OptStreamOutDmaBuf];
        bool use_userptr = options[OptStreamUser] && options[OptStreamOutUser];
-       __u32 out_type = out_fd.has_vid_m2m() ? 
v4l_type_invert(out_fd.g_type()) : out_fd.g_type();
+       __u32 out_type = out_fd.has_m2m() ? v4l_type_invert(out_fd.g_type()) : 
out_fd.g_type();
        cv4l_queue in(fd.g_type(), memory);
        cv4l_queue out(out_type, out_memory);
        fps_timestamps fps_ts[2];
@@ -3002,7 +3002,7 @@ void streaming_list(cv4l_fd &fd, cv4l_fd &out_fd)
                list_buffers(fd, fd.g_type());

        if (options[OptListBuffersOut])
-               list_buffers(*p_out_fd, p_out_fd->has_vid_m2m() ?
+               list_buffers(*p_out_fd, p_out_fd->has_m2m() ?
                             v4l_type_invert(p_out_fd->g_type()) : 
p_out_fd->g_type());

        if (options[OptStreamBufCaps])

Reply via email to