Загрузка данных


#include <linux/vmalloc.h>
#include <linux/string.h>

/* 
 * Старую функцию burst_init делаем пустой заглушкой, 
 * так как команда 0x7A теперь вшита в начало единого монолитного буфера.
 */
static int sysconfig_i2c_bitstream_burst_init(struct sysconfig_priv *priv)
{
    return 0;
}

static int sysconfig_i2c_bitstream_burst_write(struct sysconfig_priv *priv, const char *buf, size_t len)
{
    struct i2c_client *client = to_i2c_client(priv->dev);
    struct i2c_msg msg;
    const u8 lsc_cmd[] = SYSCONFIG_LSC_BITSTREAM_BURST; // {0x7a, 0x00, 0x00, 0x00}
    size_t cmd_len = sizeof(lsc_cmd);
    
    size_t aligned_payload_len;
    size_t padding_needed;
    size_t total_buffer_size;
    
    u8 *tx_buffer;
    int ret;

    if (len == 0)
        return 0;

    /* 1. Считаем выравнивание (Padding) тела прошивки до кратности 4 байтам */
    aligned_payload_len = (len + 3) & ~3; 
    padding_needed = aligned_payload_len - len;

    /* Полный размер буфера: 4 байта команды 0x7A + выровненная прошивка */
    total_buffer_size = cmd_len + aligned_payload_len;

    printk("%s(%d) [400kHz] Total payload: Raw len = %zu, Aligned len = %zu (Padding: %zu bytes)\n", 
            __FUNCTION__, __LINE__, len, aligned_payload_len, padding_needed);
    printk("%s(%d) Allocating single monolithic vmalloc buffer: %zu bytes\n", 
            __FUNCTION__, __LINE__, total_buffer_size);

    /* 2. Выделяем виртуально непрерывный буфер большой емкости */
    tx_buffer = vmalloc(total_buffer_size);
    if (!tx_buffer) {
        dev_err(priv->dev, "Failed to allocate vmalloc buffer for monolithic transfer\n");
        return -ENOMEM;
    }

    /* 3. Собираем монолитный пакет в памяти */
    /* Копируем команду начала Burst (0x7A, 0x00, 0x00, 0x00) */
    memcpy(tx_buffer, lsc_cmd, cmd_len);

    /* Копируем бинарный поток прошивки (LED_impl_1_clean_reverse.bin) */
    memcpy(tx_buffer + cmd_len, buf, len);

    /* Если нужно выравнивание, заполняем оставшийся хвостик байтами NOP (0xFF) */
    if (padding_needed > 0) {
        memset(tx_buffer + cmd_len + len, 0xFF, padding_needed);
    }

    /* 4. Конфигурируем ОДНО единственное I2C сообщение без флага NOSTART */
    msg.addr = client->addr;
    msg.flags = client->flags & I2C_M_TEN; // Обычная запись: выдаст START, адрес и погонит массив
    msg.len = total_buffer_size;
    msg.buf = tx_buffer;

    printk("%s(%d) Launching atomic monolithic i2c_transfer via DMA...\n", __FUNCTION__, __LINE__);

    /* 5. Отправляем всё за ОДИН аппаратный вызов */
    ret = i2c_transfer(client->adapter, &msg, 1);

    /* 6. Освобождаем память */
    vfree(tx_buffer);

    if (ret < 0) {
        dev_err(priv->dev, "Monolithic I2C burst write failed: %d\n", ret);
        return ret;
    }
    if (ret != 1) {
        dev_err(priv->dev, "Monolithic I2C transfer incomplete\n");
        return -EIO;
    }

    printk("%s(%d) Monolithic burst successfully finished without gaps!\n", __FUNCTION__, __LINE__);
    return 0;
}