Включение драйверов в программы пользовательского пространства/приложение SPI

Прямо сейчас я хочу использовать драйвер Cadence SPI для выполнения некоторых базовых операций чтения и записи в Linux. Я только что использовал драйвер I2C, но я все еще немного озадачен тем, как все эти драйверы сочетаются друг с другом и существует ли общий интерфейс, которому они все соответствуют.

Вот код, который я написал для использования драйвера I2C.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>

#include <errno.h>
#include <string.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

#define I2C_ADAPTER                 "/dev/i2c-0"
#define I2C_SWITHC_MUX_ADDRESS      0x74
#define DEVICE_ADDRESS              0x54


int main (int argc, char *argv[])
{
    int file;

    uint8_t reg, value;

    char *end;

    /* Take a value to write */

    printf("The device address on the bus: %d", DEVICE_ADDRESS);

    if(argc == 2) {
        value = strtol(argv[1], &end, 16);
        printf("value to write is: %d\n", value);
    }
    else {
        printf("arg failed\n\n.");
    }


    if((file = open(I2C_ADAPTER, O_RDWR)) < 0) {
        printf("Failed to open the bus\n");
        return -1;
    }

    if(ioctl(file, I2C_SLAVE_FORCE, I2C_SWITHC_MUX_ADDRESS) < 0) {
        printf("Unable to open device as slave \n%s\n", strerror(errno));
        return -1;
    }

    char buf[10];

    reg = DEVICE_ADDRESS;

    buf[0] = reg;
    buf[1] = value;

    if(write(file, buf, 2) != 2) {
        printf("Failed to write to bus %s.\n\n", strerror(errno));
    }
    else {
        printf("Successful write\n");
        printf(buf);
        printf("\n\n");
    }

    if(read(file, buf, 1) != 1) {
        printf("Failed to read from the i2c bus.\n %s\n\n", strerror(errno));
    }
    else {
        printf("Successful read\n");
        printf("Buf = [%02u]\n", buf[0]);
        printf("\n\n");
    }

    return 0;
}

Я смущен тем, где на самом деле вызывается драйвер. Теперь я читаю документы драйвера SPI здесь:

https://www.kernel.org/doc/html/v4.11/driver-api/spi.html

Соответствующие документы для драйвера I2C находятся здесь:

https://www.kernel.org/doc/html/v4.11/driver-api/i2c.html

Самая первая структура, определенная в документации I2C, — это i2c_driver. Я не думаю, что когда я писал свою программу I2C, я использовал какие-либо структуры, определенные в документе драйвера I2C. Использовал ли я когда-нибудь драйвер I2C Cadence? Если нет, то как можно переписать мою программу для использования драйвера I2C Cadence, чтобы я мог понять, как использовать драйверы в пользовательском пространстве, чтобы я мог использовать драйвер SPI.


person John Frye    schedule 06.11.2017    source источник
comment
Вы использовали драйвер I2C Cadance косвенно через драйвер i2c-dev. Этот драйвер получает уведомление всякий раз, когда адаптер I2C (главный контроллер шины I2C) добавляется или удаляется из системы, и в ответ создает или уничтожает устройства /dev/i2c-n. Это позволяет приложению в пользовательском пространстве отправлять сообщения любому ведомому устройству на шине I2C (с возможностью запутать любые ведомые устройства, привязанные к драйверу устройства).   -  person Ian Abbott    schedule 06.11.2017
comment
С помощью SPI вы можете использовать драйвер spidev для доступа к ведомому устройству SPI из пользовательского пространства, но, в отличие от I2C, ведомое устройство SPI должно быть определено в системе (например, в дереве устройств или коде конфигурации платы) и привязано к драйверу spidev. .   -  person Ian Abbott    schedule 06.11.2017
comment
Я знаю, как добавить его в дерево устройств. Но как привязать его к драйверу? Я хотел бы добавить eeprom.   -  person John Frye    schedule 06.11.2017
comment
и что это за драйверы для разработчиков? законны ли они или я должен использовать какой-то другой протокол для доступа к системе?   -  person John Frye    schedule 06.11.2017
comment
наконец, когда вы используете драйверы в пользовательском пространстве, является ли нормальным потоком 1. определение макросов, связанных с оборудованием 2. создание структур драйверов с макросами 3. вызов подпрограмм драйверов для воздействия на оборудование?   -  person John Frye    schedule 06.11.2017
comment
spidev, вероятно, не лучший выбор для доступа к eeprom. Для простого (небольшого) eeprom (не чипа флэш-памяти) at25, вероятно, лучше подходит. Для чипа флэш-памяти spi-nor, вероятно, лучше подходит, если только у вас нет контроллера флэш-памяти Cadence QSPI, который использует драйвер cadence-quadspi.   -  person Ian Abbott    schedule 06.11.2017
comment
благодаря. Я просто пытаюсь создать самое простое приложение на данный момент. Я эмулирую его на QEMU, поэтому мне нужно устройство в моем дереве устройств, которое имеет аналоги модели QEMU, такие как EEPROM. Мой следующий вопрос: как узнать, какой драйвер выбрать? Есть ли у Linux общий репозиторий или производители устройств обычно пишут свои собственные драйверы с открытым исходным кодом. Как узнать, какой драйвер лучше всего подходит для моего приложения? есть ли общий источник для всех документов по драйверам Linux?   -  person John Frye    schedule 06.11.2017
comment
Ну, я вижу, что QEMU имеет эмуляцию чипов флэш-памяти SPI в стиле m25p80, и драйвер spin-nor должен работать с ними.   -  person Ian Abbott    schedule 06.11.2017


Ответы (2)


вставлю свои пять копеек, в качестве альтернативы можно использовать утилиту i2c-tools. что позволяет очень легко иметь дело с устройствами i2c с Linux. ссылка, как его использовать. https://elinux.org/Interfacing_with_I2C_Devices

person Devidas    schedule 08.11.2017
comment
для моей фактической реализации это именно то, что я сделал. Просто не был уверен, как это будет масштабироваться и будет ли это предпочтительным способом - person John Frye; 08.11.2017
comment
одно уточнение. предоставленный вами код является пользовательским приложением (с основной функцией). код драйвера ядра создаст. узел устройства i2c-* в /dev. теперь у вас есть два варианта. используйте i2c-* из пользовательского пространства, как вы написали. и кросс-компилировать и запускать при инициализации (написать какой-нибудь скрипт инициализации). или напишите драйвер ядра, проверьте какой-нибудь драйвер rtc, чтобы сделать то же самое, спросите у ядра. решить для себя, что вы хотите сделать? - person Devidas; 08.11.2017
comment
также загляните в этот блог opensourceforu.com/2015/01/ запись-i2c-клиентов-в-linux - person Devidas; 08.11.2017

Вот как выглядит стек вызовов из пользовательского пространства через инфраструктуру ядра I2C в драйвер Cadence I2C (аналогично для read()/write()):

  1. Драйвер пользовательского пространства ioctl() вызывает compat_i2cdev_ioctl() в i2c-dev.c
  2. i2cdev_ioctl_rdwr() звонит i2c_transfer() в i2c-core-case.c
  3. __i2c_transfer() звонит adap->algo->master_xfer()

И этот указатель функции .master_xfer инициализируется обратным вызовом, определенным в i2c-cadence.c, когда вы регистрируете драйвер I2C в функции probe():

id->adap.algo = &cdns_i2c_algo;

struct i2c_algorithm cdns_i2c_algo = {
.master_xfer    = cdns_i2c_master_xfer,

Надеюсь, поможет.

person Dražen G.    schedule 10.12.2018