1010#include <linux/list.h>
1111#include <linux/module.h>
1212#include <linux/usb.h>
13+ #include <linux/usb/uvc.h>
1314#include <linux/videodev2.h>
1415
1516#include <media/v4l2-ioctl.h>
@@ -166,6 +167,71 @@ static const struct v4l2_file_operations uvc_meta_fops = {
166167 .mmap = vb2_fop_mmap ,
167168};
168169
170+ static struct uvc_entity * uvc_meta_find_msxu (struct uvc_device * dev )
171+ {
172+ static const u8 uvc_msxu_guid [16 ] = UVC_GUID_MSXU_1_5 ;
173+ struct uvc_entity * entity ;
174+
175+ list_for_each_entry (entity , & dev -> entities , list ) {
176+ if (!memcmp (entity -> guid , uvc_msxu_guid , sizeof (entity -> guid )))
177+ return entity ;
178+ }
179+
180+ return NULL ;
181+ }
182+
183+ #define MSXU_CONTROL_METADATA 0x9
184+ static int uvc_meta_detect_msxu (struct uvc_device * dev )
185+ {
186+ u32 * data __free (kfree ) = NULL ;
187+ struct uvc_entity * entity ;
188+ int ret ;
189+
190+ entity = uvc_meta_find_msxu (dev );
191+ if (!entity )
192+ return 0 ;
193+
194+ /*
195+ * USB requires buffers aligned in a special way, simplest way is to
196+ * make sure that query_ctrl will work is to kmalloc() them.
197+ */
198+ data = kmalloc (sizeof (* data ), GFP_KERNEL );
199+ if (!data )
200+ return - ENOMEM ;
201+
202+ /* Check if the metadata is already enabled. */
203+ ret = uvc_query_ctrl (dev , UVC_GET_CUR , entity -> id , dev -> intfnum ,
204+ MSXU_CONTROL_METADATA , data , sizeof (* data ));
205+ if (ret )
206+ return 0 ;
207+
208+ if (* data ) {
209+ dev -> quirks |= UVC_QUIRK_MSXU_META ;
210+ return 0 ;
211+ }
212+
213+ /*
214+ * We have seen devices that require 1 to enable the metadata, others
215+ * requiring a value != 1 and others requiring a value >1. Luckily for
216+ * us, the value from GET_MAX seems to work all the time.
217+ */
218+ ret = uvc_query_ctrl (dev , UVC_GET_MAX , entity -> id , dev -> intfnum ,
219+ MSXU_CONTROL_METADATA , data , sizeof (* data ));
220+ if (ret || !* data )
221+ return 0 ;
222+
223+ /*
224+ * If we can set MSXU_CONTROL_METADATA, the device will report
225+ * metadata.
226+ */
227+ ret = uvc_query_ctrl (dev , UVC_SET_CUR , entity -> id , dev -> intfnum ,
228+ MSXU_CONTROL_METADATA , data , sizeof (* data ));
229+ if (!ret )
230+ dev -> quirks |= UVC_QUIRK_MSXU_META ;
231+
232+ return 0 ;
233+ }
234+
169235int uvc_meta_register (struct uvc_streaming * stream )
170236{
171237 struct uvc_device * dev = stream -> dev ;
@@ -179,9 +245,14 @@ int uvc_meta_register(struct uvc_streaming *stream)
179245 & uvc_meta_fops , & uvc_meta_ioctl_ops );
180246}
181247
182- void uvc_meta_init (struct uvc_device * dev )
248+ int uvc_meta_init (struct uvc_device * dev )
183249{
184250 unsigned int i = 0 ;
251+ int ret ;
252+
253+ ret = uvc_meta_detect_msxu (dev );
254+ if (ret )
255+ return ret ;
185256
186257 dev -> meta_formats [i ++ ] = V4L2_META_FMT_UVC ;
187258
@@ -195,4 +266,6 @@ void uvc_meta_init(struct uvc_device *dev)
195266
196267 /* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */
197268 dev -> meta_formats [i ++ ] = 0 ;
269+
270+ return 0 ;
198271}
0 commit comments