原文地址:http://fpcfjf.blog.163.com/blog/static/5546979320129188402596/
今天接着讲余下的几个数据结构,主要讲spi_board_info,spi_message,spi_transfer,先看它们的定义:
1. struct spi_board_info {
2. char modalias[32]; //设备与驱动匹配的唯一标识
3. const void platform_data;
4. void *controller_data;
5. int irq;
6. u32 max_speed_hz;
7. u16 bus_num; //设备所归属的总线编号
8. u16 chip_select;
9. u8 mode;
};
boardinfo是用来管理spi_board_info的结构,spi_board_info通过spi_register_board_info(struct spi_board_info const *info, unsigned n)交由boardinfo来管理,并挂到board_list链表上,list_add_tail(&bi->list,&board_list);
[cpp] view plaincopy
1. struct boardinfo {
2. /用于挂到链表头board_list上/
3. struct list_head list;
4. /管理的spi_board_info的数量/
5. unsigned n_board_info;
6. /存放结构体spi_board_info*/
7. struct spi_board_info board_info[0];
};
1. struct spi_message {
2. struct list_head transfers; //此次消息的传输队列,一个消息可以包含多个传输段
3. struct spi_device *spi; //传输的目的设备
4. unsigned is_dma_mapped:1; //如果为真,此次调用提供dma和cpu虚拟地址
5. void (*complete)(void *context); //异步调用完成后的回调函数
6. void *context; //回调函数的参数
7. unsigned actual_length; //此次传输的实际长度
8. int status; //执行的结果,成功被置0,否则是一个负的错误码
9. struct list_head queue;
10. void *state;
};
1. struct spi_transfer {
2. const void *tx_buf; //要写入设备的数据(必须是dma_safe),或者为NULL
3. void *rx_buf; //要读取的数据缓冲(必须是dma_safe),或者为NULL
4. unsigned len; //tx和rx的大小(字节数),这里不是指它的和,而是各自的长度,他们总是相等的
5. dma_addr_t tx_dma; //如果spi_message.is_dma_mapped是真,这个是tx的dma地址
6. dma_addr_t rx_dma; //如果spi_message.is_dma_mapped是真,这个是rx的dma地址
7. unsigned cs_change:1; //影响此次传输之后的片选,指示本次tranfer结束之后是否要重新片选并调用setup改变设置,这个标志可以较少系统开销u8
8. bits_per_word; //每个字长的比特数,如果是0,使用默认值
9. u16 delay_usecs; //此次传输结束和片选改变之间的延时,之后就会启动另一个传输或者结束整个消息
10. u32 speed_hz; //通信时钟。如果是0,使用默认值
11. struct list_head transfer_list; //用来连接的双向链表节点
12. };
SPI的数据是封装到spi_transfer这个数据结构中,然后这个数据结构再封装到spi_message,,最后这个消息再挂接到spi_bitbang里面的内核提供的队列struct list_head queue上。这样,就可以实现严格的串行数据通信,保证数据的正确。
SPI通信的数据流大致是:
1、用户请求=>Protocoldriver分析请求,生成SPI通信帧=>Controllerdriver将通信帧发送到SPI总线上;
2、SPI设备传回数据=>Controllerdriver从SPI总线上读回=>Protocol解析通信数据并上报;
其中Protocol和Controller之间的交互中,SPI帧是一个比较关键的数据结构。Protocol通过分析上层请求生成这种帧,并且解析这种帧得到SPI设备的响应的结果。Controller通过和SPI总线交互,收发这样的帧。在Linux内核中,这个帧通过一个叫做spi_message的结构来实现。
在有数据请求时,Protocol解析请求生成这个帧,并发送到SPI核心子系统。SPI核心子系统通过Protocol设备的信息,找到对应的Controller设备,并将这个帧发送给Controller。Controller接受到这个帧后发送到SPI总线上。返程类似。
由浅入深,不能盲目急躁。