457bbcca1e
resolves: rhbz#2209280 Signed-off-by: Laszlo Ersek <lersek@redhat.com>
481 lines
16 KiB
Diff
481 lines
16 KiB
Diff
From ec06f62df5340cd0a9466a532aa9806fb0e2e560 Mon Sep 17 00:00:00 2001
|
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
Date: Sat, 18 Feb 2023 12:04:04 +0000
|
|
Subject: [PATCH] drivers: Look up vendor and device names in PCI and USB IDs
|
|
database
|
|
|
|
(cherry picked from commit ca21ee4918cd7d4472bd875a495752a03a03fa87)
|
|
---
|
|
.gitignore | 1 +
|
|
configure.ac | 1 +
|
|
drivers/Makefile.am | 6 +-
|
|
drivers/drivers.ml | 31 +++++
|
|
drivers/hwdata.ml | 187 +++++++++++++++++++++++++++
|
|
drivers/hwdata.mli | 31 +++++
|
|
drivers/hwdata_config.ml.in | 26 ++++
|
|
drivers/hwdata_config.mli | 35 +++++
|
|
drivers/test-virt-drivers-windows.sh | 13 +-
|
|
m4/guestfs-libraries.m4 | 3 +
|
|
po/POTFILES-ml | 2 +
|
|
11 files changed, 333 insertions(+), 3 deletions(-)
|
|
create mode 100644 drivers/hwdata.ml
|
|
create mode 100644 drivers/hwdata.mli
|
|
create mode 100644 drivers/hwdata_config.ml.in
|
|
create mode 100644 drivers/hwdata_config.mli
|
|
|
|
diff --git a/.gitignore b/.gitignore
|
|
index b0ada2e3c..c0ca330a3 100644
|
|
--- a/.gitignore
|
|
+++ b/.gitignore
|
|
@@ -95,6 +95,7 @@ Makefile.in
|
|
/customize/virt-customize
|
|
/df/virt-df
|
|
/drivers/.depend
|
|
+/drivers/hwdata_config.ml
|
|
/drivers/virt-drivers
|
|
/diff/virt-diff
|
|
/edit/virt-edit
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 34c66b80e..e9fadcc9b 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -138,6 +138,7 @@ AC_CONFIG_FILES([Makefile
|
|
df/Makefile
|
|
diff/Makefile
|
|
drivers/Makefile
|
|
+ drivers/hwdata_config.ml
|
|
edit/Makefile
|
|
format/Makefile
|
|
get-kernel/Makefile
|
|
diff --git a/drivers/Makefile.am b/drivers/Makefile.am
|
|
index d27fc2e27..7e0ef659c 100644
|
|
--- a/drivers/Makefile.am
|
|
+++ b/drivers/Makefile.am
|
|
@@ -27,9 +27,13 @@ EXTRA_DIST = \
|
|
virt-drivers.pod
|
|
|
|
SOURCES_MLI = \
|
|
- drivers.mli
|
|
+ drivers.mli \
|
|
+ hwdata_config.mli \
|
|
+ hwdata.mli
|
|
|
|
SOURCES_ML = \
|
|
+ hwdata_config.ml \
|
|
+ hwdata.ml \
|
|
drivers.ml
|
|
|
|
SOURCES_C = \
|
|
diff --git a/drivers/drivers.ml b/drivers/drivers.ml
|
|
index 57cfb557c..f02165fa4 100644
|
|
--- a/drivers/drivers.ml
|
|
+++ b/drivers/drivers.ml
|
|
@@ -235,8 +235,14 @@ and windows_hardware_to_xml = function
|
|
(Option.map (fun v -> ("class", sprintf "%06LX" v)) pci_class);
|
|
List.may_push_back attrs
|
|
(Option.map (fun v -> ("vendor", sprintf "%04LX" v)) pci_vendor);
|
|
+ let vendorname = get_pci_vendor pci_vendor in
|
|
+ List.may_push_back attrs
|
|
+ (Option.map (fun v -> "vendorname", v) vendorname);
|
|
List.may_push_back attrs
|
|
(Option.map (fun v -> ("device", sprintf "%04LX" v)) pci_device);
|
|
+ let devicename = get_pci_device pci_vendor pci_device in
|
|
+ List.may_push_back attrs
|
|
+ (Option.map (fun v -> "devicename", v) devicename);
|
|
List.may_push_back attrs
|
|
(Option.map (fun v -> ("subsystem", sprintf "%08LX" v)) pci_subsys);
|
|
List.may_push_back attrs
|
|
@@ -261,8 +267,14 @@ and windows_hardware_to_xml = function
|
|
let attrs = ref [] in
|
|
List.may_push_back attrs
|
|
(Option.map (fun v -> ("vendor", sprintf "%04LX" v)) usb_vendor);
|
|
+ let vendorname = get_usb_vendor usb_vendor in
|
|
+ List.may_push_back attrs
|
|
+ (Option.map (fun v -> "vendorname", v) vendorname);
|
|
List.may_push_back attrs
|
|
(Option.map (fun v -> ("product", sprintf "%04LX" v)) usb_product);
|
|
+ let productname = get_usb_device usb_vendor usb_product in
|
|
+ List.may_push_back attrs
|
|
+ (Option.map (fun v -> "productname", v) productname);
|
|
List.may_push_back attrs
|
|
(Option.map (fun v -> ("revision", sprintf "%02LX" v)) usb_rev);
|
|
List.may_push_back attrs
|
|
@@ -272,6 +284,25 @@ and windows_hardware_to_xml = function
|
|
| Other path ->
|
|
Comment (sprintf "unknown DeviceId: %s" (String.concat "\\" path))
|
|
|
|
+and get_pci_vendor v = get_hwdata'1 Hwdata.pci_vendor v
|
|
+and get_pci_device v d = get_hwdata'2 Hwdata.pci_device v d
|
|
+and get_usb_vendor v = get_hwdata'1 Hwdata.usb_vendor v
|
|
+and get_usb_device v d = get_hwdata'2 Hwdata.usb_device v d
|
|
+
|
|
+and get_hwdata'1 f = function
|
|
+ | Some i64 when i64 >= 0_L && i64 <= 0xffff_L ->
|
|
+ let i32 = Int64.to_int32 i64 in
|
|
+ f i32
|
|
+ | _ -> None
|
|
+
|
|
+and get_hwdata'2 f v d =
|
|
+ match v, d with
|
|
+ | Some v64, Some d64 when v64 >= 0_L && v64 <= 0xffff_L &&
|
|
+ d64 >= 0_L && d64 <= 0xffff_L ->
|
|
+ let v32 = Int64.to_int32 v64 and d32 = Int64.to_int32 d64 in
|
|
+ f v32 d32
|
|
+ | _ -> None
|
|
+
|
|
(* Main program. *)
|
|
let main () =
|
|
let add, ks = parse_cmdline () in
|
|
diff --git a/drivers/hwdata.ml b/drivers/hwdata.ml
|
|
new file mode 100644
|
|
index 000000000..4b46eff68
|
|
--- /dev/null
|
|
+++ b/drivers/hwdata.ml
|
|
@@ -0,0 +1,187 @@
|
|
+(* virt-drivers
|
|
+ * Copyright (C) 2009-2023 Red Hat Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License along
|
|
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ *)
|
|
+
|
|
+open Std_utils
|
|
+open Tools_utils
|
|
+open Common_gettext.Gettext
|
|
+
|
|
+open Printf
|
|
+open Scanf
|
|
+
|
|
+module DBKey = struct
|
|
+ type t =
|
|
+ | Vendor of int32
|
|
+ | Device of int32 * int32
|
|
+ let compare = compare
|
|
+end
|
|
+module DB = Map.Make (DBKey)
|
|
+
|
|
+let is_4_digit_hex id =
|
|
+ String.length id = 4 &&
|
|
+ Char.isxdigit id.[0] &&
|
|
+ Char.isxdigit id.[1] &&
|
|
+ Char.isxdigit id.[2] &&
|
|
+ Char.isxdigit id.[3]
|
|
+let hex_to_int32 id = sscanf id "%lx" identity
|
|
+
|
|
+(* Loads one of the [*.ids] files, returning the entries as a
|
|
+ * 3 level map. Returns [None] if the file could not be opened
|
|
+ * or parsed.
|
|
+ *)
|
|
+let load filename =
|
|
+ try
|
|
+ let lines = read_whole_file filename in
|
|
+ let lines = String.lines_split lines in
|
|
+
|
|
+ (* This loop drops blank lines and comments, splits the fields of
|
|
+ * the database, and returns [(lineno, indent, key, label) list].
|
|
+ *)
|
|
+ let rec loop lineno acc = function
|
|
+ | [] -> List.rev acc
|
|
+ (* Blank lines. *)
|
|
+ | "" :: lines ->
|
|
+ loop (lineno+1) acc lines
|
|
+ (* Note that # only starts a comment at the beginning of the line. *)
|
|
+ | comment :: lines when String.is_prefix comment "#" ->
|
|
+ loop (lineno+1) acc lines
|
|
+ (* Otherwise its some data. *)
|
|
+ | line :: lines ->
|
|
+ let len = String.length line in
|
|
+ let indent =
|
|
+ let rec counttabs i =
|
|
+ if i < len && line.[i] = '\t' then 1 + counttabs (i+1) else 0
|
|
+ in
|
|
+ counttabs 0 in
|
|
+ let line = String.sub line indent (len - indent) in
|
|
+
|
|
+ let n = String.cspan line " \t" in
|
|
+ let key, label = String.break n line in
|
|
+ let n = String.span label " \t" in
|
|
+ let _, label = String.break n label in
|
|
+
|
|
+ let acc =
|
|
+ if key = "" && label = "" then acc
|
|
+ else (lineno, indent, key, label) :: acc in
|
|
+
|
|
+ loop (lineno+1) acc lines
|
|
+ in
|
|
+ let lines = loop 1 [] lines in
|
|
+
|
|
+ (* Since the format is essentially a space-saving one where
|
|
+ * vendor name
|
|
+ * \t device name
|
|
+ * is short for:
|
|
+ * vendor name
|
|
+ * vendor device name
|
|
+ * pull the fields from previous lines down, resulting in
|
|
+ * a flat list.
|
|
+ *)
|
|
+ let rec loop keys acc = function
|
|
+ | [] -> List.rev acc
|
|
+ | (lineno, indent, key, label) :: lines ->
|
|
+ let prefix = List.take indent keys in
|
|
+ let keys = prefix @ [ key ] in
|
|
+ let acc = (lineno, keys, label) :: acc in
|
|
+ loop keys acc lines
|
|
+ in
|
|
+ let lines = loop [] [] lines in
|
|
+
|
|
+ (*
|
|
+ List.iter (
|
|
+ fun (lineno, keys, label) ->
|
|
+ eprintf "[%s] -> %s # line %d\n"
|
|
+ (String.concat ";" keys) label lineno
|
|
+ ) lines;
|
|
+ *)
|
|
+
|
|
+ (* Now we can finally process the database.
|
|
+ *
|
|
+ * We currently ignore the [C] (class) and other records
|
|
+ * that appear at the end of the file. We might want to
|
|
+ * try parsing these in future. It will require changes to
|
|
+ * the code above because the label isn't parsed right.
|
|
+ *)
|
|
+ let db =
|
|
+ List.fold_left (
|
|
+ fun db (lineno, keys, label) ->
|
|
+ let loc = filename, lineno in
|
|
+ match keys with
|
|
+ | [vendor] when is_4_digit_hex vendor ->
|
|
+ let vendor = hex_to_int32 vendor in
|
|
+ DB.add (Vendor vendor) (label, loc) db
|
|
+ | [vendor; device] when is_4_digit_hex vendor &&
|
|
+ is_4_digit_hex device ->
|
|
+ let vendor = hex_to_int32 vendor in
|
|
+ let device = hex_to_int32 device in
|
|
+ DB.add (Device (vendor, device)) (label, loc) db
|
|
+ | _ ->
|
|
+ db
|
|
+ ) DB.empty lines in
|
|
+
|
|
+ Some db
|
|
+ with exn ->
|
|
+ warning (f_"hwdata: %s: %s") filename (Printexc.to_string exn);
|
|
+ None
|
|
+
|
|
+(* Lazily load the PCI database, if present. *)
|
|
+let pci_db =
|
|
+ let filename = Hwdata_config.pci_ids in
|
|
+ lazy (match filename with None -> None | Some filename -> load filename)
|
|
+
|
|
+(* Look up PCI vendor and device ID. *)
|
|
+let pci_vendor vendor =
|
|
+ let db = Lazy.force pci_db in
|
|
+ match db with
|
|
+ | None -> None
|
|
+ | Some db ->
|
|
+ match DB.find_opt (Vendor vendor) db with
|
|
+ | None -> None
|
|
+ | Some (label, _) -> Some label
|
|
+
|
|
+let pci_device vendor device =
|
|
+ let db = Lazy.force pci_db in
|
|
+ match db with
|
|
+ | None -> None
|
|
+ | Some db ->
|
|
+ match DB.find_opt (Device (vendor, device)) db with
|
|
+ | None -> None
|
|
+ | Some (label, _) -> Some label
|
|
+
|
|
+(* Lazily load the USB database, if present. *)
|
|
+let usb_db =
|
|
+ let filename = Hwdata_config.usb_ids in
|
|
+ lazy (match filename with None -> None | Some filename -> load filename)
|
|
+
|
|
+(* Look up USB vendor and device ID. *)
|
|
+let usb_vendor vendor =
|
|
+ let db = Lazy.force usb_db in
|
|
+ match db with
|
|
+ | None -> None
|
|
+ | Some db ->
|
|
+ match DB.find_opt (Vendor vendor) db with
|
|
+ | None -> None
|
|
+ | Some (label, _) -> Some label
|
|
+
|
|
+let usb_device vendor device =
|
|
+ let db = Lazy.force usb_db in
|
|
+ match db with
|
|
+ | None -> None
|
|
+ | Some db ->
|
|
+ match DB.find_opt (Device (vendor, device)) db with
|
|
+ | None -> None
|
|
+ | Some (label, _) -> Some label
|
|
diff --git a/drivers/hwdata.mli b/drivers/hwdata.mli
|
|
new file mode 100644
|
|
index 000000000..972dfe1f6
|
|
--- /dev/null
|
|
+++ b/drivers/hwdata.mli
|
|
@@ -0,0 +1,31 @@
|
|
+(* virt-drivers
|
|
+ * Copyright (C) 2013-2023 Red Hat Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License along
|
|
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ *)
|
|
+
|
|
+(** Look up PCI and USB vendor and device IDs. *)
|
|
+
|
|
+val pci_vendor : int32 -> string option
|
|
+(** Look up the PCI vendor ID. If found, return the name. *)
|
|
+
|
|
+val pci_device : int32 -> int32 -> string option
|
|
+(** Look up the PCI vendor & device ID. If found, return the name. *)
|
|
+
|
|
+val usb_vendor : int32 -> string option
|
|
+(** Look up the USB vendor ID. If found, return the name. *)
|
|
+
|
|
+val usb_device : int32 -> int32 -> string option
|
|
+(** Look up the USB vendor & device ID. If found, return the name. *)
|
|
diff --git a/drivers/hwdata_config.ml.in b/drivers/hwdata_config.ml.in
|
|
new file mode 100644
|
|
index 000000000..fa792c086
|
|
--- /dev/null
|
|
+++ b/drivers/hwdata_config.ml.in
|
|
@@ -0,0 +1,26 @@
|
|
+(* virt-drivers
|
|
+ * @configure_input@
|
|
+ * Copyright (C) 2009-2023 Red Hat Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License along
|
|
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ *)
|
|
+
|
|
+open Std_utils
|
|
+
|
|
+let dir = "@HWDATA_PKGDATADIR@"
|
|
+let dir = if dir = "" then None else Some dir
|
|
+
|
|
+let pci_ids = Option.map (fun d -> d // "pci.ids") dir
|
|
+let usb_ids = Option.map (fun d -> d // "usb.ids") dir
|
|
diff --git a/drivers/hwdata_config.mli b/drivers/hwdata_config.mli
|
|
new file mode 100644
|
|
index 000000000..877e9e28a
|
|
--- /dev/null
|
|
+++ b/drivers/hwdata_config.mli
|
|
@@ -0,0 +1,35 @@
|
|
+(* virt-drivers
|
|
+ * Copyright (C) 2013-2023 Red Hat Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License along
|
|
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ *)
|
|
+
|
|
+val dir : string option
|
|
+(** [pkgdatadir] variable defined by hwdata.pc
|
|
+
|
|
+ This is the name of the directory containing [pci.ids] and
|
|
+ related files which contain the PCI IDs. *)
|
|
+
|
|
+val pci_ids : string option
|
|
+(** Path to the [pci.ids] file.
|
|
+
|
|
+ Note at runtime this is an optional dependency, so it may
|
|
+ not at exist even if not [None]. *)
|
|
+
|
|
+val usb_ids : string option
|
|
+(** Path to the [usb.ids] file.
|
|
+
|
|
+ Note at runtime this is an optional dependency, so it may
|
|
+ not at exist even if not [None]. *)
|
|
diff --git a/drivers/test-virt-drivers-windows.sh b/drivers/test-virt-drivers-windows.sh
|
|
index df3f36c64..4131f6e5e 100755
|
|
--- a/drivers/test-virt-drivers-windows.sh
|
|
+++ b/drivers/test-virt-drivers-windows.sh
|
|
@@ -22,9 +22,18 @@ $TEST_FUNCTIONS
|
|
skip_if_skipped
|
|
skip_unless_phony_guest windows.img
|
|
|
|
-rm -f actual-windows.xml
|
|
+rm -f actual-windows.xml actual-windows.xml.bak
|
|
|
|
$VG virt-drivers --format=raw -a ../test-data/phony-guests/windows.img > actual-windows.xml
|
|
+
|
|
+# We can't predict if hwdata is available, so we don't know if
|
|
+# vendorname and devicename fields will be present. If present,
|
|
+# remove them before comparison.
|
|
+mv actual-windows.xml actual-windows.xml.bak
|
|
+sed -e "s/ vendorname='\([^']*\)'//g" \
|
|
+ -e "s/ devicename='\([^']*\)'//g" \
|
|
+ < actual-windows.xml.bak > actual-windows.xml
|
|
+
|
|
diff -ur -I "generated by" expected-windows.xml actual-windows.xml
|
|
|
|
-rm actual-windows.xml
|
|
+rm actual-windows.xml actual-windows.xml.bak
|
|
diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4
|
|
index 2d252bf9e..32f93afda 100644
|
|
--- a/m4/guestfs-libraries.m4
|
|
+++ b/m4/guestfs-libraries.m4
|
|
@@ -169,3 +169,6 @@ PKG_CHECK_MODULES([JANSSON], [jansson >= 2.7])
|
|
|
|
dnl Check for libosinfo (mandatory)
|
|
PKG_CHECK_MODULES([LIBOSINFO], [libosinfo-1.0])
|
|
+
|
|
+dnl Check for hwdata directory (containing pci.ids) (optional, for virt-drivers)
|
|
+PKG_CHECK_VAR([HWDATA_PKGDATADIR], [hwdata], [pkgdatadir])
|
|
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
|
|
index 73984796f..7632f374d 100644
|
|
--- a/po/POTFILES-ml
|
|
+++ b/po/POTFILES-ml
|
|
@@ -79,6 +79,8 @@ dib/output_format_tgz.ml
|
|
dib/output_format_vhd.ml
|
|
dib/utils.ml
|
|
drivers/drivers.ml
|
|
+drivers/hwdata.ml
|
|
+drivers/hwdata_config.ml
|
|
get-kernel/get_kernel.ml
|
|
resize/resize.ml
|
|
sparsify/cmdline.ml
|