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


#include <linux/slab.h>

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 *msgs;
    const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST; // {0x7A, 0x00, 0x00, 0x00}
    size_t offset = 0;
    int chunk_count = 0;
    int total_msgs;
    int i, ret;

    if (len == 0)
        return 0;

    /* Вычисляем выравнивание */
    size_t aligned_len = (len + 3) & ~3;
    size_t total_padding = aligned_len - len;

    /* Считаем точное количество сообщений. Каждый чанк строго по 4096 байт! */
    /* Плюс 1 сообщение под стартовую команду 0x7A */
    total_msgs = 1 + (aligned_len + 4095) / 4096;

    msgs = kmalloc_array(total_msgs, sizeof(struct i2c_msg), GFP_KERNEL);
    if (!msgs)
        return -ENOMEM;

    printk("%s(%d) Optimized 4КB Burst: Total msgs = %d, Padding = %zu\n", 
            __FUNCTION__, __LINE__, total_msgs, total_padding);

    /* 1. Первое сообщение: строго 4 байта команды 0x7A (генерирует START) */
    msgs[chunk_count].addr = client->addr;
    msgs[chunk_count].flags = client->flags & I2C_M_TEN;
    msgs[chunk_count].len = sizeof(lsc_bitstream_burst);
    msgs[chunk_count].buf = (u8 *)lsc_bitstream_burst;
    chunk_count++;

    /* 2. Заполняем массив сообщений строго по 4096 байт с флагом NOSTART */
    while (offset < len) {
        size_t chunk_size = min((size_t)4096, len - offset);

        msgs[chunk_count].addr = client->addr;
        /* I2C_M_NOSTART заставляет контроллер i.MX95 удерживать шину непрерывно */
        msgs[chunk_count].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;

        /* Если это самый последний чанк и нужен Padding */
        if (offset + chunk_size == len && total_padding > 0) {
            size_t padded_size = chunk_size + total_padding;
            u8 *padded_buf = kmalloc(padded_size, GFP_KERNEL);
            if (!padded_buf) {
                /* Чистим за собой выделенную ранее память при ошибке */
                for (i = 1; i < chunk_count; i++) {
                    if (msgs[i].len > 4096) kfree(msgs[i].buf);
                }
                kfree(msgs);
                return -ENOMEM;
            }
            memcpy(padded_buf, buf + offset, chunk_size);
            memset(padded_buf + chunk_size, 0xFF, total_padding);

            msgs[chunk_count].len = padded_size;
            msgs[chunk_count].buf = padded_buf;
        } else {
            /* Стандартный идеальный чанк ПЕЙЛОАДА (не более 4096 байт) */
            msgs[chunk_count].len = chunk_size;
            msgs[chunk_count].buf = (u8 *)(buf + offset);
        }

        offset += chunk_size;
        chunk_count++;
    }

    printk("%s(%d) Submitting %d packets of 4KB to LPI2C engine atomically...\n", 
            __FUNCTION__, __LINE__, chunk_count);

    /* 3. Отправляем ВСЮ пачку 4КБ дескрипторов за ОДИН атомарный вызов ядра */
    ret = i2c_transfer(client->adapter, msgs, chunk_count);

    /* 4. Освобождаем выделенную память */
    if (total_padding > 0 && chunk_count > 1) {
        kfree(msgs[chunk_count - 1].buf); // Удаляем временный padded_buf последнего чанка
    }
    kfree(msgs);

    if (ret != chunk_count) {
        dev_err(priv->dev, "Atomic 4KB transfer failed: %d\n", ret);
        return (ret < 0) ? ret : -EIO;
    }

    printk("%s(%d) 4KB-aligned stream successfully flashed!\n", __FUNCTION__, __LINE__);
    return 0;
}