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


#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/sched.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 msg[2];
    const u8 lsc_burst_cmd[] = SYSCONFIG_LSC_BITSTREAM_BURST; // {0x7A, 0x00, 0x00, 0x00}
    size_t offset = 0;
    int ret;
    bool first_block = true;

    if (len == 0)
        return 0;

    size_t aligned_len = (len + 3) & ~3;
    size_t total_padding = aligned_len - len;

    printk("%s(%d) Paced 4KB DMA Loop. Raw len = %zu, Padding = %zu\n", 
            __FUNCTION__, __LINE__, len, total_padding);

    while (offset < len) {
        size_t chunk_size = min((size_t)4096, len - offset);

        if (first_block) {
            /* 
             * ШАГ 1: Стартовый блок. Отправляем команду 0x7A И первые 4096 байт вместе.
             * Используем массив из 2 сообщений, чтобы не было STOP-бита на старте.
             */
            msg[0].addr = client->addr;
            msg[0].flags = client->flags & I2C_M_TEN;
            msg[0].len = sizeof(lsc_burst_cmd);
            msg[0].buf = (u8 *)lsc_burst_cmd;

            msg[1].addr = client->addr;
            msg[1].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
            msg[1].len = chunk_size;
            msg[1].buf = (u8 *)buf;

            ret = i2c_transfer(client->adapter, msg, 2);
            if (ret != 2) {
                dev_err(priv->dev, "I2C initial burst failed: %d\n", ret);
                return (ret < 0) ? ret : -EIO;
            }
            first_block = false;
        } else {
            /* 
             * ШАГ 2: Все последующие блоки строго по 4096 байт с флагом NOSTART.
             */
            struct i2c_msg next_msg;
            u8 *padded_buf = NULL;

            next_msg.addr = client->addr;
            next_msg.flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;

            /* Если это самый последний кусок, добавляем выравнивание до 4 байт */
            if (offset + chunk_size == len && total_padding > 0) {
                size_t padded_size = chunk_size + total_padding;
                padded_buf = kmalloc(padded_size, GFP_KERNEL);
                if (!padded_buf)
                    return -ENOMEM;

                memcpy(padded_buf, buf + offset, chunk_size);
                memset(padded_buf + chunk_size, 0xFF, total_padding);

                next_msg.len = padded_size;
                next_msg.buf = padded_buf;
                
                printk("%s(%d) Sending final padded 4KB block: %zu bytes\n", __FUNCTION__, __LINE__, padded_size);
            } else {
                next_msg.len = chunk_size;
                next_msg.buf = (u8 *)(buf + offset);
            }

            ret = i2c_transfer(client->adapter, &next_msg, 1);
            
            if (padded_buf)
                kfree(padded_buf);

            if (ret != 1) {
                dev_err(priv->dev, "I2C block write failed at offset %zu: %d\n", offset, ret);
                return (ret < 0) ? ret : -EIO;
            }
        }

        offset += chunk_size;

        /* 
         * КРИТИЧЕСКИЙ МОМЕНТ ДЛЯ СКОРОСТИ:
         * Вместо долгого ухода в спячку через usleep, мы отдаем квант времени планировщику 
         * мгновенно (cond_resched) либо делаем микроскопическую аппаратную паузу в 10 микросекунд.
         * Это разгонит отправку всего файла до 3-4 секунд!
         */
        udelay(10); 
        cond_resched(); 
    }

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