media: uvcvideo: Import standard controls from uvcdynctrl
The uvcdynctrl tool from libwebcam:
https://sourceforge.net/projects/libwebcam/
maps proprietary controls into v4l2 controls using the UVCIOC_CTRL_MAP
ioctl.
The tool has not been updated for 10+ years now, and there is no reason
for the UVC driver to not do the mapping by itself.
This patch adds the mappings from the uvcdynctrl into the driver. Hopefully
this effort can help in deprecating the UVCIOC_CTRL_MAP ioctl.
Some background about UVCIOC_CTRL_MAP (thanks Laurent for the context):
```
this was envisioned as the base of a vibrant ecosystem where a large
number of vendors would submit XML files that describe their XU control
mappings, at a pace faster than could be supported by adding XU mappings
to the driver. This vision failed to materialize and the tool has not
been updated for 10+ years now. There is no reason to believe the
situation will change.
```
During the porting, the following mappings where NOT imported because
they were not using standard v4l2 IDs. It is recommended that userspace
moves to UVCIOC_CTRL_QUERY for non standard controls.
def get_single_guid(ns, constant):
id = constant.find(ns + "id").text
value = constant.find(ns + "value").text
return (id, value)
def get_constants(ns, root):
out = dict()
for constant in root.iter(ns + "constant"):
attr = constant.attrib
if attr["type"] == "integer":
id, value = get_single_guid(ns, constant)
if id in out:
print(f"dupe constant {id}")
out[id] = value
return out
def get_guids(ns, root):
out = dict()
for constant in root.iter(ns + "constant"):
attr = constant.attrib
if attr["type"] == "guid":
id, value = get_single_guid(ns, constant)
if id in out:
print(f"dupe guid {id}")
out[id] = value
return out
def get_single_control(ns, control):
out = {}
for id in "entity", "selector", "index", "size", "description":
v = control.find(ns + id)
if v is None and id == "description":
continue
out[id] = v.text
reqs = set()
for r in control.find(ns + "requests"):
reqs.add(r.text)
out["requests"] = reqs
return (control.attrib["id"], out)
def get_controls(ns, root):
out = dict()
for control in root.iter(ns + "control"):
id, value = get_single_control(ns, control)
if id in out:
print(f"Dupe control id {id}")
out[id] = value
return out
def get_single_mapping(ns, mapping):
out = {}
out["name"] = mapping.find(ns + "name").text
uvc = mapping.find(ns + "uvc")
for id in "size", "offset", "uvc_type":
out[id] = uvc.find(ns + id).text
out["control_ref"] = uvc.find(ns + "control_ref").attrib["idref"]
v4l2 = mapping.find(ns + "v4l2")
for id in "id", "v4l2_type":
out[id] = v4l2.find(ns + id).text
menu = {}
for entry in v4l2.iter(ns + "menu_entry"):
menu[entry.attrib["name"]] = entry.attrib["value"]
if menu:
out["menu"] = menu
return out
def get_mapping(ns, root):
out = []
for control in root.iter(ns + "mapping"):
mapping = get_single_mapping(ns, control)
out += [mapping]
return out
def print_guids(guids):
for g in guids:
print(f"#define {g} \\")
u_bytes = uuid.UUID(guids[g]).bytes_le
u_bytes = [f"0x{b:02x}" for b in u_bytes]
print("\t{ " + ", ".join(u_bytes) + " }")
flags = list(flags)
flags.sort()
out = ""
for f in flags[:-1]:
out += f"UVC_CTRL_FLAG_{f}\n\t\t\t\t| "
out += f"UVC_CTRL_FLAG_{flags[-1]}"
return out
def print_description(desc):
print("/*")
for line in desc.strip().splitlines():
print(f" * {line.strip()}")
print("*/")
def print_controls(controls, cons):
for id in controls:
c = controls[id]
if "description" in c:
print_description(c["description"])
print(
f"""\t{{
\t\t.entity\t\t= {c["entity"]},
\t\t.selector\t= {cons[c["selector"]]},
\t\t.index\t\t= {c["index"]},
\t\t.size\t\t= {c["size"]},
\t\t.flags\t\t= {print_flags(c["requests"])},
\t}},"""
)
def menu_mapping_txt(menu):
out = f"\n\t\t.menu_mask\t= 0x{((1<<len(menu))-1):X},\n"
out += f"\t\t.menu_mapping\t= {{ {", ".join(menu.values())} }},\n"
out += f"\t\t.menu_names\t= {{ \"{"\", \"".join(menu.keys())}\" }},\n"
return out
def print_mappings(mappings, controls, cons):
for m in mappings:
c = controls[m["control_ref"]]
def print_code(guids, cons, controls, mappings):
used_controls = set()
for m in mappings:
used_controls.add(m["control_ref"])
used_guids = set()
for c in used_controls:
used_guids.add(controls[c]["entity"])
print("\n######GUIDs#######\n")
print_guids({id: guids[id] for id in guids if id in used_guids})
print("\n######CONTROLS#######\n")
print_controls({id: controls[id] for id in controls if id in used_controls}, cons)
print("\n######MAPPINGS#######\n")
print_mappings(mappings, controls, cons)
# print(guids)
# print(used_controls)
Cc: Manav Gautama <bandwidthcrunch@gmail.com> Cc: Martin Rubli <martin_rubli@logitech.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> Reviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com> Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>