почему ioctl возвращает неверный адрес

Я использую приведенный ниже код для вывода данных из SPI-порта встроенной платы (olimex imx233-micro - это не конкретный вопрос платы). Когда я запускаю код ioctl, возвращаю "неверный адрес". Я изменяю код на http://twilight.ponies.cz/spi-test.c работает нормально. Может ли кто-нибудь сказать мне, что я делаю неправильно?

root@ubuntu:/home# gcc test.c -o test
test.c:20: warning: conflicting types for ‘msg_send’
test.c:16: note: previous implicit declaration of ‘msg_send’ was here
root@ubuntu:/home# ./test
errno:Bad address - cannot send SPI message
root@ubuntu:/home# uname -a
Linux ubuntu 3.7.1 #2 Sun Mar 17 03:49:39 CET 2013 armv5tejl GNU/Linux

Код:

//test.c
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <errno.h>

static uint16_t delay;

int main(int argc,char *argv[]){
     msg_send(254); //the message that I want to send decimal "254"
     return 0;
}

void msg_send(int msg){
    int fd;
    int ret = 0;
    fd = open("/dev/spidev32766.1", O_RDWR); //ls /dev outputs spidev32766.1
    if(fd < 0){
        fprintf(stderr, "errno:%s - FD could be not opened\n ", strerror(errno));  
        exit(1);
        }

    struct spi_ioc_transfer tr = {
        .len = 1,
        .delay_usecs = delay,
        .speed_hz = 500000, //500 kHz
        .bits_per_word = 8,
        .tx_buf = msg,
        .rx_buf = 0, //half duplex
    };

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret <1 ){
        fprintf(stderr, "errno:%s - cannot send SPI message\n ", strerror(errno));
    }
    close(fd);
}

Благодарю вас!


person sven    schedule 02.04.2013    source источник
comment
Вы знаете, что перемещение вашей функции msg_send() над main() избавит вас от этого предупреждения, верно?   -  person Mike    schedule 02.04.2013
comment
Спасибо, Майк, я был неосторожен. предупреждения исчезают, но ошибка bad address остается   -  person sven    schedule 02.04.2013
comment
.tx_buf=msg -- как вы думаете, что здесь должно произойти?   -  person n. 1.8e9-where's-my-share m.    schedule 02.04.2013
comment
н.м., я думал, что он передаст сообщение (254), которое я хочу отправить в буфер передатчика, затем оно будет отправлено через ioctl, я ошибаюсь?   -  person sven    schedule 02.04.2013


Ответы (1)


Сообщение об ошибке «Неверный адрес» возникает из-за кода ошибки EFAULT, который возникает, когда вы передаете ядру адрес, который не является допустимым виртуальным адресом в виртуальном адресном пространстве вашего процесса. Адрес вашей структуры tr явно действителен, поэтому проблема должна быть с одним из ее членов.

Согласно определение struct spi_ioc_transfer, элементы .tx_buf и .rx_buf должны быть указателями на буферы пользовательского пространства или нулевыми. Вы устанавливаете .tx_buf на целое число 254, которое не является допустимым указателем пользовательского пространства, так что отсюда исходит неверный адрес.

Я не знаком с этим IOCTL, поэтому я думаю, что вам нужно преобразовать данные в двоичный код. Один из способов сделать это:

struct spi_ioc_transfer tr = {
    .len = sizeof(msg),  // Length of rx and tx buffers
     ...
    .tx_buf = (u64)&msg, // Pointer to tx buffer
    ...
};

Если вам нужно отправить его в формате ASCII, вам следует использовать такую ​​функцию, как snprintf(3) чтобы преобразовать целое число в строку ASCII, а затем указать буфер TX на эту строку и установить соответствующую длину.

person Adam Rosenfield    schedule 02.04.2013