为什么ioctl返回“坏地址”

问题描述:

我使用下面的代码从嵌入式板的SPI端口输出数据(olimex imx233-micro - 这不是板子特定的问题)。当我运行代码ioctl返回“坏地址”。我正在修改http://twilight.ponies.cz/spi-test.c的代码,它工作正常。谁能告诉我我做错了什么?为什么ioctl返回“坏地址”

[email protected]:/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 
[email protected]:/home# ./test 
errno:Bad address - cannot send SPI message 
[email protected]:/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); 
} 

谢谢!

+2

你知道在'main()'上面移动'msg_send()'函数会摆脱那个警告吗? – Mike

+0

谢谢迈克,我粗心大意。警告消失,但“坏地址”错误依然存在 – sven

+0

'.tx_buf = msg' - 您认为应该在这里发生什么? –

错误消息“错误的地址”来自错误代码EFAULT,当您将地址传递给内核时,会发生这种情况,该内核不是进程虚拟地址空间中的有效虚拟地址。您的tr结构的地址显然是有效的,因此问题必须发生在其成员之一。

根据definition of struct spi_ioc_transfer.tx_buf和​​成员必须是指向用户空间缓冲区的指针,或者为null。您将.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缓冲区在该字符串处并相应地设置长度。

+0

非常感谢亚当!它现在运作良好 – sven