Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/misc/mei/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 18 kB image not shown  

Quelle  vsc-fw-loader.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2023, Intel Corporation.
 * Intel Visual Sensing Controller Transport Layer Linux driver
 */


#include <linux/acpi.h>
#include <linux/align.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include <linux/types.h>

#include <linux/unaligned.h>

#include "vsc-tp.h"

#define VSC_MAGIC_NUM   0x49505343 /* IPSC */
#define VSC_MAGIC_FW   0x49574653 /* IWFS */
#define VSC_MAGIC_FILE   0x46564353 /* FVCS */

#define VSC_ADDR_BASE   0xE0030000
#define VSC_EFUSE_ADDR   (VSC_ADDR_BASE + 0x038)
#define VSC_STRAP_ADDR   (VSC_ADDR_BASE + 0x100)

#define VSC_MAINSTEPPING_VERSION_MASK GENMASK(7, 4)
#define VSC_MAINSTEPPING_VERSION_A 0

#define VSC_SUBSTEPPING_VERSION_MASK GENMASK(3, 0)
#define VSC_SUBSTEPPING_VERSION_0 0
#define VSC_SUBSTEPPING_VERSION_1 2

#define VSC_BOOT_IMG_OPTION_MASK GENMASK(15, 0)

#define VSC_SKU_CFG_LOCATION  0x5001A000
#define VSC_SKU_MAX_SIZE  4100u

#define VSC_ACE_IMG_CNT   2
#define VSC_CSI_IMG_CNT   4
#define VSC_IMG_CNT_MAX   6

#define VSC_ROM_PKG_SIZE  256u
#define VSC_FW_PKG_SIZE   512u

#define VSC_IMAGE_DIR   "intel/vsc/"

#define VSC_CSI_IMAGE_NAME  VSC_IMAGE_DIR "ivsc_fw.bin"
#define VSC_ACE_IMAGE_NAME_FMT  VSC_IMAGE_DIR "ivsc_pkg_%s_0.bin"
#define VSC_CFG_IMAGE_NAME_FMT  VSC_IMAGE_DIR "ivsc_skucfg_%s_0_1.bin"

#define VSC_IMAGE_PATH_MAX_LEN  64

#define VSC_SENSOR_NAME_MAX_LEN  16

/* command id */
enum {
 VSC_CMD_QUERY = 0,
 VSC_CMD_DL_SET = 1,
 VSC_CMD_DL_START = 2,
 VSC_CMD_DL_CONT = 3,
 VSC_CMD_DUMP_MEM = 4,
 VSC_CMD_GET_CONT = 8,
 VSC_CMD_CAM_BOOT = 10,
};

/* command ack token */
enum {
 VSC_TOKEN_BOOTLOADER_REQ = 1,
 VSC_TOKEN_DUMP_RESP = 4,
 VSC_TOKEN_ERROR = 7,
};

/* image type */
enum {
 VSC_IMG_BOOTLOADER_TYPE = 1,
 VSC_IMG_CSI_EM7D_TYPE,
 VSC_IMG_CSI_SEM_TYPE,
 VSC_IMG_CSI_RUNTIME_TYPE,
 VSC_IMG_ACE_VISION_TYPE,
 VSC_IMG_ACE_CFG_TYPE,
 VSC_IMG_SKU_CFG_TYPE,
};

/* image fragments */
enum {
 VSC_IMG_BOOTLOADER_FRAG,
 VSC_IMG_CSI_SEM_FRAG,
 VSC_IMG_CSI_RUNTIME_FRAG,
 VSC_IMG_ACE_VISION_FRAG,
 VSC_IMG_ACE_CFG_FRAG,
 VSC_IMG_CSI_EM7D_FRAG,
 VSC_IMG_SKU_CFG_FRAG,
 VSC_IMG_FRAG_MAX
};

struct vsc_rom_cmd {
 __le32 magic;
 __u8 cmd_id;
 union {
  /* download start */
  struct {
   __u8 img_type;
   __le16 option;
   __le32 img_len;
   __le32 img_loc;
   __le32 crc;
   DECLARE_FLEX_ARRAY(__u8, res);
  } __packed dl_start;
  /* download set */
  struct {
   __u8 option;
   __le16 img_cnt;
   DECLARE_FLEX_ARRAY(__le32, payload);
  } __packed dl_set;
  /* download continue */
  struct {
   __u8 end_flag;
   __le16 len;
   /* 8 is the offset of payload */
   __u8 payload[VSC_ROM_PKG_SIZE - 8];
  } __packed dl_cont;
  /* dump memory */
  struct {
   __u8 res;
   __le16 len;
   __le32 addr;
   DECLARE_FLEX_ARRAY(__u8, payload);
  } __packed dump_mem;
  /* 5 is the offset of padding */
  __u8 padding[VSC_ROM_PKG_SIZE - 5];
 } data;
};

struct vsc_rom_cmd_ack {
 __le32 magic;
 __u8 token;
 __u8 type;
 __u8 res[2];
 __u8 payload[];
};

struct vsc_fw_cmd {
 __le32 magic;
 __u8 cmd_id;
 union {
  struct {
   __le16 option;
   __u8 img_type;
   __le32 img_len;
   __le32 img_loc;
   __le32 crc;
   DECLARE_FLEX_ARRAY(__u8, res);
  } __packed dl_start;
  struct {
   __le16 option;
   __u8 img_cnt;
   DECLARE_FLEX_ARRAY(__le32, payload);
  } __packed dl_set;
  struct {
   __le32 addr;
   __u8 len;
   DECLARE_FLEX_ARRAY(__u8, payload);
  } __packed dump_mem;
  struct {
   __u8 resv[3];
   __le32 crc;
   DECLARE_FLEX_ARRAY(__u8, payload);
  } __packed boot;
  /* 5 is the offset of padding */
  __u8 padding[VSC_FW_PKG_SIZE - 5];
 } data;
};

struct vsc_img {
 __le32 magic;
 __le32 option;
 __le32 image_count;
 __le32 image_location[VSC_IMG_CNT_MAX];
};

struct vsc_fw_sign {
 __le32 magic;
 __le32 image_size;
 __u8 image[];
};

struct vsc_image_code_data {
 /* fragment index */
 u8 frag_index;
 /* image type */
 u8 image_type;
};

struct vsc_img_frag {
 u8 type;
 u32 location;
 const u8 *data;
 u32 size;
};

/**
 * struct vsc_fw_loader - represent vsc firmware loader
 * @dev: device used to request firmware
 * @tp: transport layer used with the firmware loader
 * @csi: CSI image
 * @ace: ACE image
 * @cfg: config image
 * @tx_buf: tx buffer
 * @rx_buf: rx buffer
 * @option: command option
 * @count: total image count
 * @sensor_name: camera sensor name
 * @frags: image fragments
 */

struct vsc_fw_loader {
 struct device *dev;
 struct vsc_tp *tp;

 const struct firmware *csi;
 const struct firmware *ace;
 const struct firmware *cfg;

 void *tx_buf;
 void *rx_buf;

 u16 option;
 u16 count;

 char sensor_name[VSC_SENSOR_NAME_MAX_LEN];

 struct vsc_img_frag frags[VSC_IMG_FRAG_MAX];
};

static inline u32 vsc_sum_crc(void *data, size_t size)
{
 u32 crc = 0;
 size_t i;

 for (i = 0; i < size; i++)
  crc += *((u8 *)data + i);

 return crc;
}

/* get sensor name to construct image name */
static int vsc_get_sensor_name(struct vsc_fw_loader *fw_loader,
          struct device *dev)
{
 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
 union acpi_object obj = {
  .integer.type = ACPI_TYPE_INTEGER,
  .integer.value = 1,
 };
 struct acpi_object_list arg_list = {
  .count = 1,
  .pointer = &obj,
 };
 union acpi_object *ret_obj;
 acpi_handle handle;
 acpi_status status;
 int ret = 0;

 handle = ACPI_HANDLE(dev);
 if (!handle)
  return -EINVAL;

 status = acpi_evaluate_object(handle, "SID", &arg_list, &buffer);
 if (ACPI_FAILURE(status)) {
  dev_err(dev, "can't evaluate SID method: %d\n", status);
  return -ENODEV;
 }

 ret_obj = buffer.pointer;
 if (!ret_obj) {
  dev_err(dev, "can't locate ACPI buffer\n");
  return -ENODEV;
 }

 if (ret_obj->type != ACPI_TYPE_STRING) {
  dev_err(dev, "found non-string entry\n");
  ret = -ENODEV;
  goto out_free_buff;
 }

 /* string length excludes trailing NUL */
 if (ret_obj->string.length >= sizeof(fw_loader->sensor_name)) {
  dev_err(dev, "sensor name buffer too small\n");
  ret = -EINVAL;
  goto out_free_buff;
 }

 memcpy(fw_loader->sensor_name, ret_obj->string.pointer,
        ret_obj->string.length);

 string_lower(fw_loader->sensor_name, fw_loader->sensor_name);

out_free_buff:
 ACPI_FREE(buffer.pointer);

 return ret;
}

static int vsc_identify_silicon(struct vsc_fw_loader *fw_loader)
{
 struct vsc_rom_cmd_ack *ack = fw_loader->rx_buf;
 struct vsc_rom_cmd *cmd = fw_loader->tx_buf;
 u8 version, sub_version;
 int ret;

 /* identify stepping information */
 cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
 cmd->cmd_id = VSC_CMD_DUMP_MEM;
 cmd->data.dump_mem.addr = cpu_to_le32(VSC_EFUSE_ADDR);
 cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32));
 ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
 if (ret || ack->token == VSC_TOKEN_ERROR) {
  dev_err(fw_loader->dev, "CMD_DUMP_MEM error %d token %d\n", ret, ack->token);
  return ret ?: -EINVAL;
 }

 cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
 cmd->cmd_id = VSC_CMD_GET_CONT;
 ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
 if (ret || ack->token != VSC_TOKEN_DUMP_RESP) {
  dev_err(fw_loader->dev, "CMD_GETCONT error %d token %d\n", ret, ack->token);
  return ret ?: -EINVAL;
 }

 version = FIELD_GET(VSC_MAINSTEPPING_VERSION_MASK, ack->payload[0]);
 sub_version = FIELD_GET(VSC_SUBSTEPPING_VERSION_MASK, ack->payload[0]);

 if (version != VSC_MAINSTEPPING_VERSION_A) {
  dev_err(fw_loader->dev, "mainstepping mismatch expected %d got %d\n",
   VSC_MAINSTEPPING_VERSION_A, version);
  return -EINVAL;
 }

 if (sub_version != VSC_SUBSTEPPING_VERSION_0 &&
     sub_version != VSC_SUBSTEPPING_VERSION_1) {
  dev_err(fw_loader->dev, "substepping %d is out of supported range %d - %d\n",
   sub_version, VSC_SUBSTEPPING_VERSION_0, VSC_SUBSTEPPING_VERSION_1);
  return -EINVAL;
 }

 dev_info(fw_loader->dev, "silicon stepping version is %u:%u\n",
   version, sub_version);

 /* identify strap information */
 cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
 cmd->cmd_id = VSC_CMD_DUMP_MEM;
 cmd->data.dump_mem.addr = cpu_to_le32(VSC_STRAP_ADDR);
 cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32));
 ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
 if (ret)
  return ret;
 if (ack->token == VSC_TOKEN_ERROR)
  return -EINVAL;

 cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
 cmd->cmd_id = VSC_CMD_GET_CONT;
 ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
 if (ret)
  return ret;
 if (ack->token != VSC_TOKEN_DUMP_RESP)
  return -EINVAL;

 return 0;
}

static int vsc_identify_csi_image(struct vsc_fw_loader *fw_loader)
{
 const struct firmware *image;
 struct vsc_fw_sign *sign;
 struct vsc_img *img;
 unsigned int i;
 int ret;

 ret = request_firmware(&image, VSC_CSI_IMAGE_NAME, fw_loader->dev);
 if (ret)
  return ret;

 img = (struct vsc_img *)image->data;
 if (!img) {
  ret = -ENOENT;
  goto err_release_image;
 }

 if (le32_to_cpu(img->magic) != VSC_MAGIC_FILE) {
  ret = -EINVAL;
  goto err_release_image;
 }

 if (le32_to_cpu(img->image_count) != VSC_CSI_IMG_CNT) {
  ret = -EINVAL;
  goto err_release_image;
 }
 fw_loader->count += le32_to_cpu(img->image_count) - 1;

 fw_loader->option =
  FIELD_GET(VSC_BOOT_IMG_OPTION_MASK, le32_to_cpu(img->option));

 sign = (struct vsc_fw_sign *)
  (img->image_location + le32_to_cpu(img->image_count));

 for (i = 0; i < VSC_CSI_IMG_CNT; i++) {
  /* mapping from CSI image index to image code data */
  static const struct vsc_image_code_data csi_image_map[] = {
   { VSC_IMG_BOOTLOADER_FRAG, VSC_IMG_BOOTLOADER_TYPE },
   { VSC_IMG_CSI_SEM_FRAG, VSC_IMG_CSI_SEM_TYPE },
   { VSC_IMG_CSI_RUNTIME_FRAG, VSC_IMG_CSI_RUNTIME_TYPE },
   { VSC_IMG_CSI_EM7D_FRAG, VSC_IMG_CSI_EM7D_TYPE },
  };
  struct vsc_img_frag *frag;

  if ((u8 *)sign + sizeof(*sign) > image->data + image->size) {
   ret = -EINVAL;
   goto err_release_image;
  }

  if (le32_to_cpu(sign->magic) != VSC_MAGIC_FW) {
   ret = -EINVAL;
   goto err_release_image;
  }

  if (!le32_to_cpu(img->image_location[i])) {
   ret = -EINVAL;
   goto err_release_image;
  }

  frag = &fw_loader->frags[csi_image_map[i].frag_index];

  frag->data = sign->image;
  frag->size = le32_to_cpu(sign->image_size);
  frag->location = le32_to_cpu(img->image_location[i]);
  frag->type = csi_image_map[i].image_type;

  sign = (struct vsc_fw_sign *)
   (sign->image + le32_to_cpu(sign->image_size));
 }

 fw_loader->csi = image;

 return 0;

err_release_image:
 release_firmware(image);

 return ret;
}

static int vsc_identify_ace_image(struct vsc_fw_loader *fw_loader)
{
 char path[VSC_IMAGE_PATH_MAX_LEN];
 const struct firmware *image;
 struct vsc_fw_sign *sign;
 struct vsc_img *img;
 unsigned int i;
 int ret;

 snprintf(path, sizeof(path), VSC_ACE_IMAGE_NAME_FMT,
   fw_loader->sensor_name);

 ret = request_firmware(&image, path, fw_loader->dev);
 if (ret)
  return ret;

 img = (struct vsc_img *)image->data;
 if (!img) {
  ret = -ENOENT;
  goto err_release_image;
 }

 if (le32_to_cpu(img->magic) != VSC_MAGIC_FILE) {
  ret = -EINVAL;
  goto err_release_image;
 }

 if (le32_to_cpu(img->image_count) != VSC_ACE_IMG_CNT) {
  ret = -EINVAL;
  goto err_release_image;
 }
 fw_loader->count += le32_to_cpu(img->image_count);

 sign = (struct vsc_fw_sign *)
  (img->image_location + le32_to_cpu(img->image_count));

 for (i = 0; i < VSC_ACE_IMG_CNT; i++) {
  /* mapping from ACE image index to image code data */
  static const struct vsc_image_code_data ace_image_map[] = {
   { VSC_IMG_ACE_VISION_FRAG, VSC_IMG_ACE_VISION_TYPE },
   { VSC_IMG_ACE_CFG_FRAG, VSC_IMG_ACE_CFG_TYPE },
  };
  struct vsc_img_frag *frag, *last_frag;
  u8 frag_index;

  if ((u8 *)sign + sizeof(*sign) > image->data + image->size) {
   ret = -EINVAL;
   goto err_release_image;
  }

  if (le32_to_cpu(sign->magic) != VSC_MAGIC_FW) {
   ret = -EINVAL;
   goto err_release_image;
  }

  frag_index = ace_image_map[i].frag_index;
  frag = &fw_loader->frags[frag_index];

  frag->data = sign->image;
  frag->size = le32_to_cpu(sign->image_size);
  frag->location = le32_to_cpu(img->image_location[i]);
  frag->type = ace_image_map[i].image_type;

  if (!frag->location) {
   last_frag = &fw_loader->frags[frag_index - 1];
   frag->location =
    ALIGN(last_frag->location + last_frag->size, SZ_4K);
  }

  sign = (struct vsc_fw_sign *)
   (sign->image + le32_to_cpu(sign->image_size));
 }

 fw_loader->ace = image;

 return 0;

err_release_image:
 release_firmware(image);

 return ret;
}

static int vsc_identify_cfg_image(struct vsc_fw_loader *fw_loader)
{
 struct vsc_img_frag *frag = &fw_loader->frags[VSC_IMG_SKU_CFG_FRAG];
 char path[VSC_IMAGE_PATH_MAX_LEN];
 const struct firmware *image;
 u32 size;
 int ret;

 snprintf(path, sizeof(path), VSC_CFG_IMAGE_NAME_FMT,
   fw_loader->sensor_name);

 ret = request_firmware(&image, path, fw_loader->dev);
 if (ret)
  return ret;

 /* identify image size */
 if (image->size <= sizeof(u32) || image->size > VSC_SKU_MAX_SIZE) {
  ret = -EINVAL;
  goto err_release_image;
 }

 size = le32_to_cpu(*((__le32 *)image->data)) + sizeof(u32);
 if (image->size != size) {
  ret = -EINVAL;
  goto err_release_image;
 }

 frag->data = image->data;
 frag->size = image->size;
 frag->type = VSC_IMG_SKU_CFG_TYPE;
 frag->location = VSC_SKU_CFG_LOCATION;

 fw_loader->cfg = image;

 return 0;

err_release_image:
 release_firmware(image);

 return ret;
}

static int vsc_download_bootloader(struct vsc_fw_loader *fw_loader)
{
 struct vsc_img_frag *frag = &fw_loader->frags[VSC_IMG_BOOTLOADER_FRAG];
 struct vsc_rom_cmd_ack *ack = fw_loader->rx_buf;
 struct vsc_rom_cmd *cmd = fw_loader->tx_buf;
 u32 len, c_len;
 size_t remain;
 const u8 *p;
 int ret;

 cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
 cmd->cmd_id = VSC_CMD_QUERY;
 ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
 if (ret)
  return ret;
 if (ack->token != VSC_TOKEN_DUMP_RESP &&
     ack->token != VSC_TOKEN_BOOTLOADER_REQ)
  return -EINVAL;

 cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
 cmd->cmd_id = VSC_CMD_DL_START;
 cmd->data.dl_start.option = cpu_to_le16(fw_loader->option);
 cmd->data.dl_start.img_type = frag->type;
 cmd->data.dl_start.img_len = cpu_to_le32(frag->size);
 cmd->data.dl_start.img_loc = cpu_to_le32(frag->location);

 c_len = offsetof(struct vsc_rom_cmd, data.dl_start.crc);
 cmd->data.dl_start.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));

 ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_ROM_PKG_SIZE);
 if (ret)
  return ret;

 p = frag->data;
 remain = frag->size;

 /* download image data */
 while (remain > 0) {
  len = min(remain, sizeof(cmd->data.dl_cont.payload));

  cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
  cmd->cmd_id = VSC_CMD_DL_CONT;
  cmd->data.dl_cont.len = cpu_to_le16(len);
  cmd->data.dl_cont.end_flag = remain == len;
  memcpy(cmd->data.dl_cont.payload, p, len);

  ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_ROM_PKG_SIZE);
  if (ret)
   return ret;

  p += len;
  remain -= len;
 }

 return 0;
}

static int vsc_download_firmware(struct vsc_fw_loader *fw_loader)
{
 struct vsc_fw_cmd *cmd = fw_loader->tx_buf;
 unsigned int i, index = 0;
 u32 c_len;
 int ret;

 cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
 cmd->cmd_id = VSC_CMD_DL_SET;
 cmd->data.dl_set.img_cnt = cpu_to_le16(fw_loader->count);
 put_unaligned_le16(fw_loader->option, &cmd->data.dl_set.option);

 for (i = VSC_IMG_CSI_SEM_FRAG; i <= VSC_IMG_CSI_EM7D_FRAG; i++) {
  struct vsc_img_frag *frag = &fw_loader->frags[i];

  cmd->data.dl_set.payload[index++] = cpu_to_le32(frag->location);
  cmd->data.dl_set.payload[index++] = cpu_to_le32(frag->size);
 }

 c_len = offsetof(struct vsc_fw_cmd, data.dl_set.payload[index]);
 cmd->data.dl_set.payload[index] = cpu_to_le32(vsc_sum_crc(cmd, c_len));

 ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
 if (ret)
  return ret;

 for (i = VSC_IMG_CSI_SEM_FRAG; i < VSC_IMG_FRAG_MAX; i++) {
  struct vsc_img_frag *frag = &fw_loader->frags[i];
  const u8 *p;
  u32 remain;

  cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
  cmd->cmd_id = VSC_CMD_DL_START;
  cmd->data.dl_start.img_type = frag->type;
  cmd->data.dl_start.img_len = cpu_to_le32(frag->size);
  cmd->data.dl_start.img_loc = cpu_to_le32(frag->location);
  put_unaligned_le16(fw_loader->option, &cmd->data.dl_start.option);

  c_len = offsetof(struct vsc_fw_cmd, data.dl_start.crc);
  cmd->data.dl_start.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));

  ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
  if (ret)
   return ret;

  p = frag->data;
  remain = frag->size;

  /* download image data */
  while (remain > 0) {
   u32 len = min(remain, VSC_FW_PKG_SIZE);

   memcpy(fw_loader->tx_buf, p, len);
   memset(fw_loader->tx_buf + len, 0, VSC_FW_PKG_SIZE - len);

   ret = vsc_tp_rom_xfer(fw_loader->tp, fw_loader->tx_buf,
           NULL, VSC_FW_PKG_SIZE);
   if (ret)
    break;

   p += len;
   remain -= len;
  }
 }

 cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
 cmd->cmd_id = VSC_CMD_CAM_BOOT;

 c_len = offsetof(struct vsc_fw_cmd, data.dl_start.crc);
 cmd->data.boot.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));

 return vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
}

/**
 * vsc_tp_init - init vsc_tp
 * @tp: vsc_tp device handle
 * @dev: device node for mei vsc device
 * Return: 0 in case of success, negative value in case of error
 */

int vsc_tp_init(struct vsc_tp *tp, struct device *dev)
{
 struct vsc_fw_loader *fw_loader __free(kfree) = NULL;
 void *tx_buf __free(kfree) = NULL;
 void *rx_buf __free(kfree) = NULL;
 int ret;

 fw_loader = kzalloc(sizeof(*fw_loader), GFP_KERNEL);
 if (!fw_loader)
  return -ENOMEM;

 tx_buf = kzalloc(VSC_FW_PKG_SIZE, GFP_KERNEL);
 if (!tx_buf)
  return -ENOMEM;

 rx_buf = kzalloc(VSC_FW_PKG_SIZE, GFP_KERNEL);
 if (!rx_buf)
  return -ENOMEM;

 fw_loader->tx_buf = tx_buf;
 fw_loader->rx_buf = rx_buf;

 fw_loader->tp = tp;
 fw_loader->dev = dev;

 ret = vsc_get_sensor_name(fw_loader, dev);
 if (ret)
  return ret;

 ret = vsc_identify_silicon(fw_loader);
 if (ret)
  return ret;

 ret = vsc_identify_csi_image(fw_loader);
 if (ret)
  return ret;

 ret = vsc_identify_ace_image(fw_loader);
 if (ret)
  goto err_release_csi;

 ret = vsc_identify_cfg_image(fw_loader);
 if (ret)
  goto err_release_ace;

 ret = vsc_download_bootloader(fw_loader);
 if (!ret)
  ret = vsc_download_firmware(fw_loader);

 release_firmware(fw_loader->cfg);

err_release_ace:
 release_firmware(fw_loader->ace);

err_release_csi:
 release_firmware(fw_loader->csi);

 return ret;
}
EXPORT_SYMBOL_NS_GPL(vsc_tp_init, "VSC_TP");

Messung V0.5
C=97 H=81 G=89

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.