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


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);
    const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST;
    struct i2c_msg *msgs;
    size_t offset = 0;
    int chunk_count = 0;
    int ret;

    if (len == 0)
        return 0;

    /* Вычисляем выровненный размер (кратно 4 байтам) */
    size_t aligned_len = (len + 3) & ~3; 
    size_t padding_needed = aligned_len - len;

    /* Считаем количество сообщений на основе ALIGNED_LEN */
    int 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) Raw len = %zu, Aligned len = %zu (Padding: %zu bytes)\n", 
            __FUNCTION__, __LINE__, len, aligned_len, padding_needed);

    /* 1. Сообщение команды BURST */
    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. Заполнение стандартных полных чанков по 4КБ */
    while (offset < len) {
        size_t chunk_size = min((size_t)4096, len - offset);

        /* Если это самый последний кусок и требуется выравнивание */
        if (offset + chunk_size == len && padding_needed > 0) {
            /* Выделяем временный буфер для последнего чанка, чтобы безопасно дописать 0xFF */
            size_t final_chunk_size = chunk_size + padding_needed;
            u8 *padded_buf = kmalloc(final_chunk_size, GFP_KERNEL);
            if (!padded_buf) {
                kfree(msgs);
                return -ENOMEM;
            }

            /* Копируем остаток оригинальных данных */
            memcpy(padded_buf, buf + offset, chunk_size);
            /* Забиваем хвост фиктивными байтами NOP (0xFF) */
            memset(padded_buf + chunk_size, 0xFF, padding_needed);

            msgs[chunk_count].addr = client->addr;
            msgs[chunk_count].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
            msgs[chunk_count].len = final_chunk_size;
            msgs[chunk_count].buf = padded_buf;
            
            /* Важно: этот буфер нужно будет освободить после i2c_transfer! */
        } else {
            /* Обычный промежуточный чанк */
            msgs[chunk_count].addr = client->addr;
            msgs[chunk_count].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
            msgs[chunk_count].len = chunk_size;
            msgs[chunk_count].buf = (u8 *)(buf + offset);
        }

        offset += chunk_size;
        chunk_count++;
    }

    /* 3. Атомарная отправка */
    ret = i2c_transfer(client->adapter, msgs, chunk_count);
    
    /* 4. Чистим за собой выделенную память */
    if (padding_needed > 0 && chunk_count > 1) {
        kfree(msgs[chunk_count - 1].buf); // Освобождаем временный padded_buf
    }
    kfree(msgs);

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

    return 0;
}