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;
size_t chunk_size = 4096;
int num_msgs, i, ret;
u8 *padded_buf = NULL;
if (len == 0)
return 0;
size_t aligned_len = (len + 3) & ~3;
size_t total_padding = aligned_len - len;
/* 1 сообщение под команду + N сообщений под данные */
int data_chunks = (len + chunk_size - 1) / chunk_size;
num_msgs = 1 + data_chunks;
msgs = kmalloc_array(num_msgs, sizeof(struct i2c_msg), GFP_KERNEL);
if (!msgs)
return -ENOMEM;
// Сообщение 0: Команда инициализации BURST (Генерирует START)
msgs[0].addr = client->addr;
msgs[0].flags = client->flags & I2C_M_TEN;
msgs[0].len = sizeof(lsc_bitstream_burst);
msgs[0].buf = (u8 *)lsc_bitstream_burst;
// Заполняем сообщения для чанков данных
for (i = 1; i <= data_chunks; i++) {
size_t current_chunk = min(chunk_size, len - offset);
msgs[i].addr = client->addr;
/* Все последующие сообщения удерживают шину без повторного START */
msgs[i].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
/* Проверяем, последний ли это чанк и нужен ли padding */
if (offset + current_chunk == len && total_padding > 0) {
size_t padded_size = current_chunk + total_padding;
padded_buf = kmalloc(padded_size, GFP_KERNEL);
if (!padded_buf) {
ret = -ENOMEM;
goto free_msgs;
}
memcpy(padded_buf, buf + offset, current_chunk);
memset(padded_buf + current_chunk, 0xFF, total_padding);
msgs[i].len = padded_size;
msgs[i].buf = padded_buf;
} else {
msgs[i].len = current_chunk;
msgs[i].buf = (u8 *)(buf + offset);
}
offset += current_chunk;
}
/* Отправляем ВСЮ прошивку за один атомарный шаг подсистемы I2C */
ret = i2c_transfer(client->adapter, msgs, num_msgs);
if (ret == num_msgs) {
ret = 0;
printk("%s(%d) Burst stream successfully transmitted\n", __FUNCTION__, __LINE__);
} else {
dev_err(priv->dev, "I2C single-pass burst transfer failed: %d\n", ret);
ret = (ret < 0) ? ret : -EIO;
}
free_msgs:
kfree(padded_buf);
kfree(msgs);
return ret;
}