/********************************************************** Prototype void spi_data_queue_init ( void ) Type function Description init buffer and data variable ***********************************************************/ void spi_data_queue_init(void) { int i; void *p_virtual_buff; unsigned int buffer_offset[SPI_DATA_QUEUE_TYPE_NB] = { FMT_OUT, FMT_IN, RAW_OUT, RAW_IN, RFS_OUT, RFS_IN}; p_virtual_buff = ipc_spi_get_queue_buff(); spi_queue = p_virtual_buff+sizeof(struct spi_data_queue)*2; spi_queue_info = (struct spi_data_queue_info *) spi_os_vmalloc( sizeof(struct spi_data_queue_info)*SPI_DATA_QUEUE_TYPE_NB); spi_os_memset(spi_queue_info, 0x00, sizeof(struct spi_data_queue_info)*SPI_DATA_QUEUE_TYPE_NB); spi_div_buf = (struct spi_data_div_buf *) spi_os_vmalloc( sizeof(struct spi_data_div_buf)*SPI_DATA_QUEUE_TYPE_NB); spi_os_memset(spi_div_buf, 0x00, sizeof(struct spi_data_div_buf) *SPI_DATA_QUEUE_TYPE_NB); gspi_data_prepare_packet = (char *) spi_os_vmalloc( SPI_DEV_MAX_PACKET_SIZE); gspi_data_packet_buf = (char *) spi_os_malloc(SPI_DEV_MAX_PACKET_SIZE); for (i = 0 ; i < SPI_DATA_QUEUE_TYPE_NB ; i++) { spi_queue_info[i].header = &spi_queue[i]; switch (i) { case SPI_DATA_QUEUE_TYPE_IPC_TX: case SPI_DATA_QUEUE_TYPE_IPC_RX: spi_queue_info[i].buf_size = SPI_DATA_IPC_QUEUE_SIZE; spi_queue_info[i].type = SPI_DATA_MUX_IPC; spi_div_buf[i].buffer = (char *)spi_os_vmalloc( SPI_DATA_IPC_DIV_BUFFER_SIZE); break; case SPI_DATA_QUEUE_TYPE_RAW_TX: case SPI_DATA_QUEUE_TYPE_RAW_RX: spi_queue_info[i].buf_size = SPI_DATA_RAW_QUEUE_SIZE; spi_queue_info[i].type = SPI_DATA_MUX_RAW; spi_div_buf[i].buffer = (char *)spi_os_vmalloc( SPI_DATA_RAW_DIV_BUFFER_SIZE); break; case SPI_DATA_QUEUE_TYPE_RFS_TX: case SPI_DATA_QUEUE_TYPE_RFS_RX: spi_queue_info[i].buf_size = SPI_DATA_RFS_QUEUE_SIZE; spi_queue_info[i].type = SPI_DATA_MUX_RFS; spi_div_buf[i].buffer = (char *)spi_os_vmalloc( SPI_DATA_RFS_DIV_BUFFER_SIZE); break; } if (spi_queue_info[i].buffer == 0) spi_queue_info[i].buffer = (char *)(p_virtual_buff + buffer_offset[i]); } }
/********************************************************** Prototype unsigned int _pack_spi_data (SPI_DATA_TYPE_T type,void * buf, void * data, unsigned int length) Type static function Description pack data for spi Param input type : type of data type buf : address of buffer to be saved data : address of data to pack length : length of input data Return value length of packed data ***********************************************************/ static unsigned int _pack_spi_data(enum SPI_DATA_TYPE_T type, void *buf, void *data, unsigned int length) { char *spi_packet = NULL; unsigned int out_length = 0; spi_packet = (char *) buf; spi_os_memset((char *)spi_packet, 0x00, (unsigned int)length); spi_os_memset((char *)spi_packet, (unsigned char)SPI_DATA_BOF, SPI_DATA_BOF_SIZE); spi_os_memcpy((char *)spi_packet + SPI_DATA_BOF_SIZE, data, length); spi_os_memset((char *)spi_packet + SPI_DATA_BOF_SIZE + length, (unsigned char)SPI_DATA_EOF, SPI_DATA_EOF_SIZE); out_length = SPI_DATA_BOF_SIZE + length + SPI_DATA_EOF_SIZE; return out_length; }
int spi_data_parsing_rx_packet(void *buf, unsigned int length) { struct spi_data_packet_header *spi_packet_header; char *spi_packet; unsigned int spi_packet_length; unsigned int spi_packet_cur_pos = SPI_DATA_PACKET_HEADER_SIZE; unsigned int spi_data_mux; unsigned int spi_data_length; char *spi_cur_data; struct spi_data_queue_info *queue_info; struct spi_data_div_buf *tx_div_buf; /* check spi packet header */ if (*(unsigned int *)buf == 0x00000000 || *(unsigned int *)buf == 0xFFFFFFFF) { /* if spi header is invalid, */ /* read spi header again with next 4 byte */ buf += SPI_DATA_PACKET_HEADER_SIZE; } spi_packet = (char *) buf; /* read spi packet header */ spi_packet_header = (struct spi_data_packet_header *) buf; spi_packet_length = SPI_DATA_PACKET_HEADER_SIZE + spi_packet_header->current_data_size; do { /* read spi data mux and set current queue */ spi_os_memcpy(&spi_data_mux, spi_packet + spi_packet_cur_pos, SPI_DATA_MUX_SIZE); switch (spi_data_mux & SPI_DATA_MUX_NORMAL_MASK) { case SPI_DATA_MUX_IPC: queue_info = &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX]; tx_div_buf = &spi_div_buf[SPI_DATA_QUEUE_TYPE_IPC_RX]; break; case SPI_DATA_MUX_RAW: queue_info = &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX]; tx_div_buf = &spi_div_buf[SPI_DATA_QUEUE_TYPE_RAW_RX]; break; case SPI_DATA_MUX_RFS: queue_info = &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_RX]; tx_div_buf = &spi_div_buf[SPI_DATA_QUEUE_TYPE_RFS_RX]; break; default: pr_err("%s len[%u], pos[%u]\n", "[SPI] ERROR : spi_data_parsing_rx_packet : MUX error", spi_packet_length, spi_packet_cur_pos); spi_os_trace_dump_low("mux error", spi_packet + spi_packet_cur_pos, 16); return spi_packet_cur_pos - SPI_DATA_PACKET_HEADER_SIZE; } /* read spi data length */ spi_os_memcpy(&spi_data_length, spi_packet + spi_packet_cur_pos + SPI_DATA_LENGTH_OFFSET, SPI_DATA_LENGTH_SIZE); if (spi_data_mux & SPI_DATA_MUX_MORE_H || spi_data_mux & SPI_DATA_MUX_MORE_M) spi_data_length += SPI_DATA_HEADER_SIZE_FRONT; else if (spi_data_mux & SPI_DATA_MUX_MORE_T) spi_data_length += SPI_DATA_HEADER_SIZE; else spi_data_length += SPI_DATA_HEADER_SIZE; /* read data and make spi data */ spi_cur_data = spi_packet + spi_packet_cur_pos; /* verify spi data */ if (_spi_data_verify(spi_cur_data, spi_data_mux) == 0) { spi_packet_cur_pos += spi_data_length; continue; } /* inqueue rx buffer */ if (spi_data_mux & SPI_DATA_MUX_MORE_H || spi_data_mux & SPI_DATA_MUX_MORE_M) { /* middle of divided packet. save to rx_div_buf */ spi_os_memcpy((void *)(tx_div_buf->buffer + tx_div_buf->length), spi_cur_data, spi_data_length); tx_div_buf->length += (spi_data_length - SPI_DATA_HEADER_SIZE_FRONT); } else if (spi_data_mux & SPI_DATA_MUX_MORE_T) { unsigned int spi_origine_len = 0; /* tail of divided packet. save to rx_div_buf */ spi_os_memcpy((void *)(tx_div_buf->buffer + tx_div_buf->length), spi_cur_data, spi_data_length); tx_div_buf->length += spi_data_length; /* update spi data length at spi header */ spi_origine_len = tx_div_buf->length - SPI_DATA_HEADER_SIZE; spi_os_memcpy(tx_div_buf->buffer + SPI_DATA_LENGTH_OFFSET, &(spi_origine_len), SPI_DATA_LENGTH_SIZE); /* inqueue from rx_div_buf */ spi_data_inqueue(queue_info, tx_div_buf->buffer, tx_div_buf->length); spi_os_memset(tx_div_buf->buffer, 0, SPI_DATA_DIVIDE_BUFFER_SIZE); tx_div_buf->length = 0; } else { /* normal packet */ spi_data_inqueue(queue_info, spi_cur_data, spi_data_length); } /* move spi packet current posision */ spi_packet_cur_pos += spi_data_length; } while ((spi_packet_length - 1) > spi_packet_cur_pos); return 1; }
static int _prepare_tx_type_packet(void *buf, struct spi_data_queue_info *queue_info, struct spi_data_div_buf *spi_data_buf, enum SPI_DATA_TYPE_T spi_type) { char *spi_packet; struct spi_data_packet_header *spi_packet_header; unsigned int spi_packet_free_length; unsigned int spi_packet_count = 0; unsigned int cur_dequeue_length; unsigned int spi_data_mux; struct spi_data_queue *queue; queue = queue_info->header; spi_packet = (char *)buf; spi_packet_header = (struct spi_data_packet_header *)buf; spi_packet_free_length = SPI_DATA_PACKET_MAX_PACKET_BODY_SIZE - spi_packet_header->current_data_size; /* not enough space in spi packet */ /* spi_packet_header->current_data_size > 2022(2048 - 16) */ if (spi_packet_header->current_data_size > SPI_DATA_PACKET_MAX_PACKET_BODY_SIZE - SPI_DATA_MIN_SIZE) { if (spi_data_check_tx_queue() == 1) spi_packet_header->more = 1; return 0; } while ((queue->head != queue->tail) || (spi_data_buf->length > 0)) { spi_os_memset(gspi_data_prepare_packet, 0, SPI_DEV_MAX_PACKET_SIZE); cur_dequeue_length = 0; /* dequeue SPI data */ if (spi_data_buf->length > 0) { if ((*(unsigned int *)spi_data_buf->buffer) == SPI_DATA_FF_PADDING_HEADER) { /* if data has 0xFF padding header */ /* send packet directly */ spi_os_memcpy(spi_packet, spi_data_buf->buffer, spi_data_buf->length); spi_data_buf->length = 0; return 0; } else { /* read from tx div buf */ spi_os_memcpy(gspi_data_prepare_packet, spi_data_buf->buffer, spi_data_buf->length); cur_dequeue_length = spi_data_buf->length; spi_data_buf->length = 0; } } else { /* read from tx queue */ cur_dequeue_length = spi_data_dequeue(queue_info, gspi_data_prepare_packet); } if (cur_dequeue_length < 0) continue; if (spi_packet_free_length < cur_dequeue_length) { spi_os_memcpy(spi_data_buf->buffer, gspi_data_prepare_packet, cur_dequeue_length); spi_data_buf->length = cur_dequeue_length; spi_packet_header->more = 1; return 0; } /* check mux value */ spi_os_memcpy(&spi_data_mux, gspi_data_prepare_packet, SPI_DATA_MUX_SIZE); if (spi_data_mux == 0) spi_os_memcpy(gspi_data_prepare_packet, &spi_type, SPI_DATA_MUX_SIZE); spi_os_memcpy(spi_packet + SPI_DATA_PACKET_HEADER_SIZE + spi_packet_header->current_data_size, gspi_data_prepare_packet, cur_dequeue_length); /* update header */ spi_packet_header->current_data_size += cur_dequeue_length; spi_packet_free_length -= cur_dequeue_length; /* increase spi packet count */ spi_packet_count++; /* check spi packet size */ if (spi_packet_free_length < SPI_DATA_MIN_SIZE) { if (spi_data_check_tx_queue() == 1) spi_packet_header->more = 1; return 0; } /* check spi maximum count per packet */ if (spi_packet_count >= SPI_DATA_MAX_COUNT_PER_PACKET) { pr_err("%s %s\n", "[SPI] ERROR : spi _prepare_tx_type_packet :", "spi_packet_count is full"); return 0; } } return spi_packet_header->current_data_size + SPI_DATA_PACKET_HEADER_SIZE; }