mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-01 21:02:27 +00:00
Currently, when we jump from RO to RW, we forget our USB PD state. To recover from this, we send a SOFT_RESET (resetting the counters...), then either the USB PD partner is happy about it and we can continue, or it will issue a HARD_RESET to recover from our mismatched vision of the current connection (e.g wrong role) resulting in a reset of VBUS. The following use-case is still problematic: if the system is not write-protected (ie it does USB PD negotiation in RO EC) and we have no battery (or fully drained-one) as buffer, when we are connected to a PD power supply, if it issues the HARD_RESET mentioned above, we are going to brown-out. It's happening with power-supplies supporting DR_SWAP, the RO EC will negotiate a power-contract (as a sink), then try to reverse data role (from UFP to DFP) to identify the power-supply. We end-up being Sink/DFP, then when we sysjump to RW, we reset roles and send the SOFT_RESET as Sink/DFP, the power-supply identifies the incorrect data role and issues the HARD_RESET browning us out. As a workaround, now we never ask for the DR_SWAP in RO firmware and stays Sink/UFP. This is not affecting regular write-protected machines (which are not doing USB PD in RO EC). For developers, we are no longer doing the DR_SWAP in RO mode, this is mostly innocuous for a regular power-supply, but this would break the docking use-case. Normally, we will do it as soon as we have jumped to RW, so the dock should still work unless the developer is using the machine with RO EC (eg EC development with soft-sync disabled). Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=reef BUG=b:35648282 TEST=Boot Snappy without battery. Verify RO image doesn't swap data roles and soft reset issued by RW image as SNK/UFP is accepted by the HP adapter. Change-Id: Id184f0d24a006cd46212d04ceae02f640f5bda65 Reviewed-on: https://chromium-review.googlesource.com/461142 Commit-Ready: Daisuke Nojiri <dnojiri@chromium.org> Tested-by: Daisuke Nojiri <dnojiri@chromium.org> Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Reviewed-by: Sam Hurst <shurst@google.com>
553 lines
12 KiB
C
553 lines
12 KiB
C
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#define _GNU_SOURCE /* for asprintf */
|
|
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <dirent.h>
|
|
#include <stdint.h>
|
|
#include <limits.h>
|
|
|
|
#include "config.h"
|
|
#include "usb_pd.h"
|
|
#include "usb_pd_tcpm.h"
|
|
#include "charge_manager.h"
|
|
#include "system.h"
|
|
|
|
#define PD_REV_2_0 1
|
|
#define PD_REV_3_0 2
|
|
|
|
#define VIF_SPEC "Revision 1.11, Version 1.0"
|
|
#define VENDOR_NAME "Google"
|
|
#define PD_SPEC_REV PD_REV_2_0
|
|
|
|
enum dtype {SNK = 0, SRC = 3, DRP = 4};
|
|
|
|
const uint32_t vdo_idh __attribute__((weak)) = 0;
|
|
|
|
const uint32_t *src_pdo;
|
|
uint32_t src_pdo_cnt;
|
|
|
|
char *yes_no(int val)
|
|
{
|
|
return val ? "YES" : "NO";
|
|
}
|
|
|
|
enum system_image_copy_t system_get_image_copy(void)
|
|
{
|
|
return SYSTEM_IMAGE_RW;
|
|
}
|
|
|
|
static void init_src_pdos(void)
|
|
{
|
|
#ifdef CONFIG_USB_PD_DYNAMIC_SRC_CAP
|
|
src_pdo_cnt = charge_manager_get_source_pdo(&src_pdo);
|
|
#else
|
|
src_pdo_cnt = pd_src_pdo_cnt;
|
|
src_pdo = pd_src_pdo;
|
|
#endif
|
|
}
|
|
|
|
static int is_src(void)
|
|
{
|
|
return src_pdo_cnt;
|
|
}
|
|
|
|
static int is_snk(void)
|
|
{
|
|
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
|
return pd_snk_pdo_cnt;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static int is_extpwr(void)
|
|
{
|
|
if (is_src())
|
|
return !!(src_pdo[0] & PDO_FIXED_EXTERNAL);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static int is_drp(void)
|
|
{
|
|
if (is_src())
|
|
return !!(src_pdo[0] & PDO_FIXED_DUAL_ROLE);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
|
static char *giveback(void)
|
|
{
|
|
#ifdef CONFIG_USB_PD_GIVE_BACK
|
|
return "YES";
|
|
#else
|
|
return "NO";
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
static char *is_comms_cap(void)
|
|
{
|
|
if (is_src())
|
|
return yes_no(src_pdo[0] & PDO_FIXED_COMM_CAP);
|
|
else
|
|
return "NO";
|
|
}
|
|
|
|
static char *dr_swap_to_ufp_supported(void)
|
|
{
|
|
if (src_pdo[0] & PDO_FIXED_DATA_SWAP)
|
|
return yes_no(pd_check_data_swap(0, PD_ROLE_DFP));
|
|
|
|
return "NO";
|
|
}
|
|
|
|
static char *dr_swap_to_dfp_supported(void)
|
|
{
|
|
if (src_pdo[0] & PDO_FIXED_DATA_SWAP)
|
|
return yes_no(pd_check_data_swap(0, PD_ROLE_UFP));
|
|
|
|
return "NO";
|
|
}
|
|
|
|
static char *vconn_swap(void)
|
|
{
|
|
#ifdef CONFIG_USBC_VCONN_SWAP
|
|
return "YES";
|
|
#else
|
|
return "NO";
|
|
#endif
|
|
}
|
|
|
|
static char *try_src(void)
|
|
{
|
|
#ifdef CONFIG_USB_PD_TRY_SRC
|
|
return "YES";
|
|
#else
|
|
return "NO";
|
|
#endif
|
|
}
|
|
|
|
static char *can_act_as_host(void)
|
|
{
|
|
#ifdef CONFIG_VIF_TYPE_C_CAN_ACT_AS_HOST
|
|
return "YES";
|
|
#else
|
|
return "NO";
|
|
#endif
|
|
}
|
|
|
|
static char *can_act_as_device(void)
|
|
{
|
|
#ifdef CONFIG_USB
|
|
return "YES";
|
|
#else
|
|
return "NO";
|
|
#endif
|
|
}
|
|
|
|
static char *captive_cable(void)
|
|
{
|
|
#ifdef CONFIG_VIF_CAPTIVE_CABLE
|
|
return "YES";
|
|
#else
|
|
return "NO";
|
|
#endif
|
|
}
|
|
|
|
static char *sources_vconn(void)
|
|
{
|
|
#ifdef CONFIG_USBC_VCONN
|
|
return "YES";
|
|
#else
|
|
return "NO";
|
|
#endif
|
|
}
|
|
|
|
static char *battery_powered(void)
|
|
{
|
|
#if defined(CONFIG_BATTERY_BQ20Z453) || defined(CONFIG_BATTERY_BQ27541) || \
|
|
defined(CONFIG_BATTERY_BQ27621) || defined(CONFIG_BATTERY_RYU) || \
|
|
defined(CONFIG_BATTERY_SAMUS) || defined(CONFIG_BATTERY_SMART)
|
|
return "YES";
|
|
#else
|
|
return "NO";
|
|
#endif
|
|
}
|
|
|
|
static uint32_t product_type(void)
|
|
{
|
|
return PD_IDH_PTYPE(vdo_idh);
|
|
}
|
|
|
|
static uint32_t pid_sop(void)
|
|
{
|
|
#ifdef CONFIG_USB_PID
|
|
return CONFIG_USB_PID;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static uint32_t rp_value(void)
|
|
{
|
|
#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT
|
|
return CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static char *attempts_discov_sop(enum dtype type)
|
|
{
|
|
#ifdef CONFIG_USB_PD_SIMPLE_DFP
|
|
if (type == SRC)
|
|
return "NO";
|
|
else
|
|
return "YES";
|
|
#else
|
|
return "YES";
|
|
#endif
|
|
}
|
|
|
|
static uint32_t bcddevice_sop(void)
|
|
{
|
|
#ifdef CONFIG_USB_BCD_DEV
|
|
return CONFIG_USB_BCD_DEV;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static uint32_t write_pdo_to_vif(FILE *vif, uint32_t pdo,
|
|
enum dtype type, uint32_t pnum)
|
|
{
|
|
uint32_t power;
|
|
|
|
if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_FIXED) {
|
|
uint32_t current = pdo & 0x3ff;
|
|
uint32_t voltage = (pdo >> 10) & 0x3ff;
|
|
|
|
power = ((current * 10) * (voltage * 50)) / 1000;
|
|
|
|
fprintf(vif, "%s_PDO_Supply_Type%d: 0\r\n",
|
|
(type == SRC) ? "Src" : "Snk", pnum);
|
|
if (type == SRC)
|
|
fprintf(vif, "Src_PDO_Peak_Current%d: 0\r\n", pnum);
|
|
fprintf(vif, "%s_PDO_Voltage%d: %d\r\n",
|
|
(type == SRC) ? "Src" : "Snk", pnum, voltage);
|
|
if (type == SRC)
|
|
fprintf(vif, "Src_PDO_Max_Current%d: %d\r\n",
|
|
pnum, current);
|
|
else
|
|
fprintf(vif, "Snk_PDO_Op_Current%d: %d\r\n",
|
|
pnum, current);
|
|
} else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) {
|
|
uint32_t max_voltage = (pdo >> 20) & 0x3ff;
|
|
uint32_t min_voltage = (pdo >> 10) & 0x3ff;
|
|
|
|
power = pdo & 0x3ff;
|
|
|
|
fprintf(vif, "%s_PDO_Supply_Type%d: 1\r\n",
|
|
(type == SRC) ? "Src" : "Snk", pnum);
|
|
fprintf(vif, "%s_PDO_Min_Voltage%d: %d\r\n",
|
|
(type == SRC) ? "Src" : "Snk", pnum, min_voltage);
|
|
fprintf(vif, "%s_PDO_Max_Voltage%d: %d\r\n",
|
|
(type == SRC) ? "Src" : "Snk", pnum, max_voltage);
|
|
if (type == SRC)
|
|
fprintf(vif, "Src_PDO_Max_Power%d: %d\r\n",
|
|
pnum, power);
|
|
else
|
|
fprintf(vif, "Snk_PDO_Op_Power%d: %d\r\n",
|
|
pnum, power);
|
|
} else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_VARIABLE) {
|
|
uint32_t max_voltage = (pdo >> 20) & 0x3ff;
|
|
uint32_t min_voltage = (pdo >> 10) & 0x3ff;
|
|
uint32_t current = pdo & 0x3ff;
|
|
|
|
power = ((current * 10) * (max_voltage * 50)) / 1000;
|
|
|
|
fprintf(vif, "%s_PDO_Supply_Type%d: 2\r\n",
|
|
(type == SRC) ? "Src" : "Snk", pnum);
|
|
if (type == SRC)
|
|
fprintf(vif, "Src_PDO_Peak_Current%d: 0\r\n", pnum);
|
|
fprintf(vif, "%s_PDO_Min_Voltage%d: %d\r\n",
|
|
(type == SRC) ? "Src" : "Snk", pnum, min_voltage);
|
|
fprintf(vif, "%s_PDO_Max_Voltage%d: %d\r\n",
|
|
(type == SRC) ? "Src" : "Snk", pnum, max_voltage);
|
|
if (type == SRC)
|
|
fprintf(vif, "Src_PDO_Max_Current%d: %d\r\n",
|
|
pnum, current);
|
|
else
|
|
fprintf(vif, "Snk_PDO_Op_Current%d: %d\r\n",
|
|
pnum, current);
|
|
}
|
|
|
|
return power;
|
|
}
|
|
|
|
/**
|
|
* Carriage and line feed, '\r\n', is needed because the file is processed
|
|
* on a Windows machine.
|
|
*/
|
|
static int gen_vif(const char *name, const char *board,
|
|
const char *vif_producer)
|
|
{
|
|
FILE *vif;
|
|
enum dtype type;
|
|
|
|
if (is_drp())
|
|
type = DRP;
|
|
else if (is_src() && is_snk())
|
|
/* No DRP with SRC and SNK PDOs detected. So ignore. */
|
|
/* ie. Twinki or Plankton */
|
|
return 0;
|
|
else if (is_src())
|
|
type = SRC;
|
|
else if (is_snk())
|
|
type = SNK;
|
|
else
|
|
return 1;
|
|
|
|
/* Create VIF */
|
|
vif = fopen(name, "w+");
|
|
if (vif == NULL)
|
|
return 1;
|
|
|
|
/* Write VIF Header */
|
|
fprintf(vif, "$VIF_Specification: \"%s\"\r\n", VIF_SPEC);
|
|
fprintf(vif, "$VIF_Producer: \"%s\"\r\n", vif_producer);
|
|
fprintf(vif, "$Vendor_name: \"%s\"\r\n", VENDOR_NAME);
|
|
fprintf(vif, "$Product_Name: \"%s\"\r\n", board);
|
|
|
|
fprintf(vif, "PD_Specification_Revision: %d\r\n", PD_SPEC_REV);
|
|
fprintf(vif, "UUT_Device_Type: %d\r\n", type);
|
|
fprintf(vif, "USB_Comms_Capable: %s\r\n", is_comms_cap());
|
|
fprintf(vif, "DR_Swap_To_DFP_Supported: %s\r\n",
|
|
dr_swap_to_dfp_supported());
|
|
fprintf(vif, "DR_Swap_To_UFP_Supported: %s\r\n",
|
|
dr_swap_to_ufp_supported());
|
|
fprintf(vif, "Externally_Powered: %s\r\n", yes_no(is_extpwr()));
|
|
fprintf(vif, "VCONN_Swap_To_On_Supported: %s\r\n", vconn_swap());
|
|
fprintf(vif, "VCONN_Swap_To_Off_Supported: %s\r\n", vconn_swap());
|
|
fprintf(vif, "Responds_To_Discov_SOP: YES\r\n");
|
|
fprintf(vif, "Attempts_Discov_SOP: %s\r\n", attempts_discov_sop(type));
|
|
fprintf(vif, "SOP_Capable: YES\r\n");
|
|
fprintf(vif, "SOP_P_Capable: NO\r\n");
|
|
fprintf(vif, "SOP_PP_Capable: NO\r\n");
|
|
fprintf(vif, "SOP_P_Debug_Capable: NO\r\n");
|
|
fprintf(vif, "SOP_PP_Debug_Capable: NO\r\n");
|
|
|
|
/* Write Source Fields */
|
|
if (type == DRP || type == SRC) {
|
|
uint32_t max_power = 0;
|
|
|
|
fprintf(vif, "USB_Suspend_May_Be_Cleared: YES\r\n");
|
|
fprintf(vif, "Sends_Pings: NO\r\n");
|
|
fprintf(vif, "Num_Src_PDOs: %d\r\n", src_pdo_cnt);
|
|
|
|
/* Write Source PDOs */
|
|
{
|
|
int i;
|
|
uint32_t pwr;
|
|
|
|
for (i = 0; i < src_pdo_cnt; i++) {
|
|
pwr = write_pdo_to_vif(vif, src_pdo[i],
|
|
SRC, i+1);
|
|
if (pwr > max_power)
|
|
max_power = pwr;
|
|
}
|
|
}
|
|
|
|
fprintf(vif, "PD_Power_as_Source: %d\r\n", max_power);
|
|
}
|
|
|
|
/* Write Sink Fields */
|
|
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
|
if (type == DRP || type == SNK) {
|
|
uint32_t max_power = 0;
|
|
uint32_t pwr;
|
|
int i;
|
|
|
|
fprintf(vif, "USB_Suspend_May_Be_Cleared: NO\r\n");
|
|
fprintf(vif, "GiveBack_May_Be_Set: %s\r\n", giveback());
|
|
fprintf(vif, "Higher_Capability_Set: NO\r\n");
|
|
fprintf(vif, "Num_Snk_PDOs: %d\r\n", pd_snk_pdo_cnt);
|
|
|
|
/* Write Sink PDOs */
|
|
for (i = 0; i < pd_snk_pdo_cnt; i++) {
|
|
pwr = write_pdo_to_vif(vif, pd_snk_pdo[i], SNK, i+1);
|
|
if (pwr > max_power)
|
|
max_power = pwr;
|
|
}
|
|
|
|
fprintf(vif, "PD_Power_as_Sink: %d\r\n", max_power);
|
|
}
|
|
|
|
/* Write DRP Fields */
|
|
if (type == DRP) {
|
|
fprintf(vif, "Accepts_PR_Swap_As_Src: YES\r\n");
|
|
fprintf(vif, "Accepts_PR_Swap_As_Snk: YES\r\n");
|
|
fprintf(vif, "Requests_PR_Swap_As_Src: YES\r\n");
|
|
fprintf(vif, "Requests_PR_Swap_As_Snk: YES\r\n");
|
|
}
|
|
#endif
|
|
|
|
/* SOP Discovery Fields */
|
|
fprintf(vif, "Structured_VDM_Version_SOP: 0\r\n");
|
|
fprintf(vif, "XID_SOP: 0\r\n");
|
|
fprintf(vif, "Data_Capable_as_USB_Host_SOP: %s\r\n",
|
|
can_act_as_host());
|
|
fprintf(vif, "Data_Capable_as_USB_Device_SOP: %s\r\n",
|
|
can_act_as_device());
|
|
fprintf(vif, "Product_Type_SOP: %d\r\n", product_type());
|
|
fprintf(vif, "Modal_Operation_Supported_SOP: YES\r\n");
|
|
fprintf(vif, "USB_VID_SOP: 0x%04x\r\n", USB_VID_GOOGLE);
|
|
fprintf(vif, "PID_SOP: 0x%04x\r\n", pid_sop());
|
|
fprintf(vif, "bcdDevice_SOP: 0x%04x\r\n", bcddevice_sop());
|
|
|
|
fprintf(vif, "SVID1_SOP: 0x%04x\r\n", USB_VID_GOOGLE);
|
|
fprintf(vif, "SVID1_num_modes_min_SOP: 1\r\n");
|
|
fprintf(vif, "SVID1_num_modes_max_SOP: 1\r\n");
|
|
fprintf(vif, "SVID1_num_modes_fixed_SOP: YES\r\n");
|
|
fprintf(vif, "SVID1_mode1_enter_SOP: YES\r\n");
|
|
|
|
#ifdef USB_SID_DISPLAYPORT
|
|
fprintf(vif, "SVID2_SOP: 0x%04x\r\n", USB_SID_DISPLAYPORT);
|
|
fprintf(vif, "SVID2_num_modes_min_SOP: 2\r\n");
|
|
fprintf(vif, "SVID2_num_modes_max_SOP: 2\r\n");
|
|
fprintf(vif, "SVID2_num_modes_fixed_SOP: YES\r\n");
|
|
fprintf(vif, "SVID2_mode1_enter_SOP: YES\r\n");
|
|
fprintf(vif, "SVID2_mode2_enter_SOP: YES\r\n");
|
|
|
|
fprintf(vif, "Num_SVIDs_min_SOP: 2\r\n");
|
|
fprintf(vif, "Num_SVIDs_max_SOP: 2\r\n");
|
|
fprintf(vif, "SVID_fixed_SOP: YES\r\n");
|
|
#else
|
|
fprintf(vif, "Num_SVIDs_min_SOP: 1\r\n");
|
|
fprintf(vif, "Num_SVIDs_max_SOP: 1\r\n");
|
|
fprintf(vif, "SVID_fixed_SOP: YES\r\n");
|
|
#endif
|
|
|
|
/* set Type_C_State_Machine */
|
|
{
|
|
int typec;
|
|
|
|
switch (type) {
|
|
case DRP:
|
|
typec = 2;
|
|
break;
|
|
|
|
case SNK:
|
|
typec = 1;
|
|
break;
|
|
|
|
default:
|
|
typec = 0;
|
|
}
|
|
|
|
fprintf(vif, "Type_C_State_Machine: %d\r\n", typec);
|
|
}
|
|
|
|
fprintf(vif, "Type_C_Implements_Try_SRC: %s\r\n", try_src());
|
|
fprintf(vif, "Type_C_Implements_Try_SNK: NO\r\n");
|
|
fprintf(vif, "Rp_Value: %d\r\n", rp_value());
|
|
/* None of the current devices send SOP' / SOP", so NO.*/
|
|
fprintf(vif, "Type_C_Supports_VCONN_Powered_Accessory: NO\r\n");
|
|
fprintf(vif, "Type_C_Is_VCONN_Powered_Accessory: NO\r\n");
|
|
fprintf(vif, "Type_C_Can_Act_As_Host: %s\r\n", can_act_as_host());
|
|
fprintf(vif, "Type_C_Host_Speed: 4\r\n");
|
|
fprintf(vif, "Type_C_Can_Act_As_Device: %s\r\n", can_act_as_device());
|
|
fprintf(vif, "Type_C_Device_Speed: 4\r\n");
|
|
fprintf(vif, "Type_C_Power_Source: 2\r\n");
|
|
fprintf(vif, "Type_C_BC_1_2_Support: 1\r\n");
|
|
fprintf(vif, "Type_C_Battery_Powered: %s\r\n", battery_powered());
|
|
fprintf(vif, "Type_C_Port_On_Hub: NO\r\n");
|
|
fprintf(vif, "Type_C_Supports_Audio_Accessory: NO\r\n");
|
|
fprintf(vif, "Captive_Cable: %s\r\n", captive_cable());
|
|
fprintf(vif, "Type_C_Source_Vconn: %s\r\n", sources_vconn());
|
|
|
|
fclose(vif);
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int nopt;
|
|
int ret;
|
|
const char *out;
|
|
const char *board;
|
|
const char *vif_producer;
|
|
DIR *vifdir;
|
|
char *name;
|
|
int name_size;
|
|
const char * const short_opt = "hb:o:";
|
|
const struct option long_opts[] = {
|
|
{ "help", 0, NULL, 'h' },
|
|
{ "board", 1, NULL, 'b' },
|
|
{ "out", 1, NULL, 'o' },
|
|
{ NULL }
|
|
};
|
|
|
|
vif_producer = argv[0];
|
|
|
|
do {
|
|
nopt = getopt_long(argc, argv, short_opt, long_opts, NULL);
|
|
switch (nopt) {
|
|
case 'h': /* -h or --help */
|
|
printf("USAGE: %s -b <board name> -o <out directory>\n",
|
|
vif_producer);
|
|
return 1;
|
|
|
|
case 'b': /* -b or --board */
|
|
board = optarg;
|
|
break;
|
|
|
|
case 'o': /* -o or --out */
|
|
out = optarg;
|
|
break;
|
|
|
|
case -1:
|
|
break;
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
} while (nopt != -1);
|
|
|
|
if (out == NULL || board == NULL)
|
|
return 1;
|
|
|
|
/* Make sure VIF directory exists */
|
|
vifdir = opendir(out);
|
|
if (vifdir == NULL) {
|
|
fprintf(stderr, "ERROR: %s directory does not exist.\n", out);
|
|
return 1;
|
|
}
|
|
closedir(vifdir);
|
|
|
|
init_src_pdos();
|
|
|
|
name_size = asprintf(&name, "%s/%s_vif.txt", out, board);
|
|
if (name_size < 0) {
|
|
fprintf(stderr, "ERROR: Out of memory.\n");
|
|
return 1;
|
|
}
|
|
|
|
ret = gen_vif(name, board, vif_producer);
|
|
|
|
free(name);
|
|
|
|
return ret;
|
|
}
|