/* * Copyright (C) 2021 Richard Hughes * Copyright (C) 2017 Christian J. Kellner * Copyright (C) 2020 Mario Limonciello * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include #include "fu-thunderbolt-common.h" #include "fu-thunderbolt-retimer.h" struct _FuThunderboltRetimer { FuThunderboltDevice parent_instance; }; G_DEFINE_TYPE(FuThunderboltRetimer, fu_thunderbolt_retimer, FU_TYPE_THUNDERBOLT_DEVICE) static FuUdevDevice * fu_thunderbolt_retimer_get_udev_grandparent(FuDevice *device, GError **error) { g_autoptr(GUdevDevice) udev_parent1 = NULL; g_autoptr(GUdevDevice) udev_parent2 = NULL; GUdevDevice *udev_device = NULL; FuThunderboltRetimer *self = FU_THUNDERBOLT_RETIMER(device); udev_device = fu_udev_device_get_dev(FU_UDEV_DEVICE(device)); if (udev_device == NULL) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to get udev device for retimer"); return NULL; } udev_parent1 = g_udev_device_get_parent(udev_device); if (udev_parent1 == NULL) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to get parent device for retimer"); return NULL; } udev_parent2 = g_udev_device_get_parent(udev_parent1); if (udev_parent2 == NULL) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to get host router device for retimer"); return NULL; } return fu_udev_device_new(fu_device_get_context(FU_DEVICE(self)), g_steal_pointer(&udev_parent2)); } gboolean fu_thunderbolt_retimer_set_parent_port_offline(FuDevice *device, GError **error) { g_autoptr(FuUdevDevice) parent = fu_thunderbolt_retimer_get_udev_grandparent(device, error); if (parent == NULL) return FALSE; return fu_thunderbolt_udev_set_port_offline(parent, error); } gboolean fu_thunderbolt_retimer_set_parent_port_online(FuDevice *device, GError **error) { g_autoptr(FuUdevDevice) parent = fu_thunderbolt_retimer_get_udev_grandparent(device, error); if (parent == NULL) return FALSE; return fu_thunderbolt_udev_set_port_online(parent, error); } static gboolean fu_thunderbolt_retimer_probe(FuDevice *device, GError **error) { const gchar *devpath = fu_udev_device_get_sysfs_path(FU_UDEV_DEVICE(device)); g_autofree gchar *physical_id = g_path_get_basename(devpath); /* device */ if (physical_id != NULL) fu_device_set_physical_id(device, physical_id); return TRUE; } static gboolean fu_thunderbolt_retimer_setup(FuDevice *device, GError **error) { FuThunderboltRetimer *self = FU_THUNDERBOLT_RETIMER(device); guint16 did; guint16 vid; g_autofree gchar *instance = NULL; /* get version */ if (!fu_thunderbolt_device_get_version(FU_THUNDERBOLT_DEVICE(self), error)) return FALSE; /* as defined in PCIe 4.0 spec */ vid = fu_udev_device_get_vendor(FU_UDEV_DEVICE(self)); if (vid == 0x0) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "missing vendor id"); return FALSE; } did = fu_udev_device_get_model(FU_UDEV_DEVICE(self)); if (did == 0x0) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "missing device id"); return FALSE; } instance = g_strdup_printf("TBT-%04x%04x-retimer%s", (guint)vid, (guint)did, fu_device_get_physical_id(device)); fu_device_add_instance_id(device, instance); /* hardcoded for now: * 1. unsure if ID_VENDOR_FROM_DATABASE works in this instance * 2. we don't recognize anyone else yet */ if (fu_device_get_vendor(device) == NULL) fu_device_set_vendor(device, "Intel"); /* success */ return TRUE; } static void fu_thunderbolt_retimer_init(FuThunderboltRetimer *self) { fu_device_set_name(FU_DEVICE(self), "USB4 Retimer"); fu_device_set_summary( FU_DEVICE(self), "A physical layer protocol-aware, software-transparent extension device " "that forms two separate electrical link segments"); fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_internal_flag(FU_DEVICE(self), FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE); } static void fu_thunderbolt_retimer_class_init(FuThunderboltRetimerClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass); klass_device->setup = fu_thunderbolt_retimer_setup; klass_device->probe = fu_thunderbolt_retimer_probe; }