/********************************************************** Prototype int spi_data_inqueue (struct spi_data_queue_info * queue_info, void * data, unsigned int length ) Type function Description inqueue data to spi rx or tx buffer Param input queue_info : queue for inqueue data : address of data lenth : length of data Return value 0 : fail 1 : success ***********************************************************/ int spi_data_inqueue(struct spi_data_queue_info *queue_info, void *data, unsigned int length) { char *pdata; struct spi_data_queue *queue; pdata = data; queue = queue_info->header; if (queue->tail < queue->head) { if ((queue->head - queue->tail) < length) { pr_err("%s%s[%u],%s[%u],%s[%u],%s[%u]\n", "[SPI] ERROR : spi_data_inqueue : ", "queue is overflow head", queue->head, "tail", queue->tail, "length", length, "buf_size", queue_info->buf_size); return -1; } } else { if ((queue_info->buf_size - (queue->tail - queue->head)) < length) { pr_err("%s%s[%u],%s[%u],%s[%u],%s[%u]\n", "[SPI] ERROR : spi_data_inqueue : queue is overflow ", "head", queue->head, "tail", queue->tail, "request length", length, "buf_size", queue_info->buf_size); return -1; } } if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX] == queue_info || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_RX] == queue_info) { pdata += (SPI_DATA_MUX_SIZE+SPI_DATA_LENGTH_SIZE); length -= (SPI_DATA_MUX_SIZE+SPI_DATA_LENGTH_SIZE); } if (queue_info->buf_size < (queue->tail + length)) { /* maximum < tail + length */ unsigned int pre_data_len = 0; pre_data_len = queue_info->buf_size - queue->tail; spi_os_memcpy(queue_info->buffer + queue->tail, pdata, pre_data_len); spi_os_memcpy(queue_info->buffer, pdata + pre_data_len, length - pre_data_len); queue->tail = ((queue->tail+length)%queue_info->buf_size); } else if (queue_info->buf_size == (queue->tail + length)) { /* maximum == tail + length */ spi_os_memcpy((queue_info->buffer + queue->tail), (char *)pdata, length); queue->tail = 0; } else { /* maximum > tail + length */ spi_os_memcpy((queue_info->buffer + queue->tail), (char *)pdata, length); queue->tail = queue->tail + length; } return 1; }
static int _spi_data_verify(void *buf, unsigned int mux) { unsigned int length; unsigned int max_data_len = SPI_DATA_MAX_SIZE_PER_PACKET; char bof = 0x00; char eof = 0x00; spi_os_memcpy(&length, (char *)buf+SPI_DATA_LENGTH_OFFSET, SPI_DATA_LENGTH_SIZE); spi_os_memcpy(&bof, (char *)buf+SPI_DATA_BOF_OFFSET, SPI_DATA_BOF_SIZE); if (mux & SPI_DATA_MUX_MORE_H || mux & SPI_DATA_MUX_MORE_M) max_data_len += SPI_DATA_EOF_SIZE; if (bof == SPI_DATA_BOF) { if (length <= max_data_len) { if (mux & SPI_DATA_MUX_MORE_H || mux & SPI_DATA_MUX_MORE_M) return 1; else { spi_os_memcpy(&eof, (char *)buf+SPI_DATA_EOF_OFFSET(length), SPI_DATA_EOF_SIZE); if (eof != SPI_DATA_EOF) { pr_err("%s %s\n", "[SPI] ERROR : _spi_data_verify:", "invalid"); return 0; } } } else { pr_err("%s %s\n", "[SPI] ERROR : _spi_data_verify:", "invalid : length error"); return 0; } } else { pr_err("%s %s\n", "[SPI] ERROR : _spi_data_verify:", "invalid : bof error"); return 0; } return 1; }
/********************************************************** 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; }
unsigned int spi_data_dequeue(struct spi_data_queue_info *queue_info, void *pdata) { unsigned int length = 0, buf_length, pre_data_len; struct spi_data_queue *queue; queue = queue_info->header; if (queue->tail == queue->head) { /* empty */ pr_err("[SPI] ERROR : spi_data_dequeue: queue is empty\n"); return -1; } if (queue->head == queue_info->buf_size) queue->head = 0; /* check length of data */ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info || &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info) { /* IPC Case */ if (queue_info->buf_size == (queue->head + SPI_DATA_BOF_SIZE)) { /* maximum == head + pos_len */ spi_os_memcpy(&length, queue_info->buffer, SPI_DATA_IPC_INNER_LENGTH_SIZE); } else if (queue_info->buf_size < (queue->head + SPI_DATA_BOF_SIZE + SPI_DATA_IPC_INNER_LENGTH_SIZE)) { /* maximum < head + pos_len */ char data_header[SPI_DATA_IPC_INNER_LENGTH_SIZE] = {0,}; pre_data_len = queue_info->buf_size - queue->head - SPI_DATA_BOF_SIZE; spi_os_memcpy(data_header, (queue_info->buffer + queue->head + SPI_DATA_BOF_SIZE), pre_data_len); spi_os_memcpy(data_header + pre_data_len, queue_info->buffer, SPI_DATA_IPC_INNER_LENGTH_SIZE - pre_data_len); spi_os_memcpy(&length, data_header, SPI_DATA_IPC_INNER_LENGTH_SIZE); } else { /* maximum > head + pos_len */ spi_os_memcpy(&length, (queue_info->buffer + queue->head + SPI_DATA_BOF_SIZE), SPI_DATA_IPC_INNER_LENGTH_SIZE); } } else { /* RAW, RFS Case */ if (queue_info->buf_size == (queue->head + SPI_DATA_BOF_SIZE)) { /* maximum == head + pos_len */ spi_os_memcpy(&length, queue_info->buffer, SPI_DATA_INNER_LENGTH_SIZE); } else if (queue_info->buf_size < (queue->head + SPI_DATA_BOF_SIZE + SPI_DATA_INNER_LENGTH_SIZE)) { /* maximum < head + pos_len */ char data_header[SPI_DATA_INNER_LENGTH_SIZE] = {0,}; pre_data_len = queue_info->buf_size - queue->head - SPI_DATA_BOF_SIZE; spi_os_memcpy(data_header, (queue_info->buffer + queue->head + SPI_DATA_BOF_SIZE), pre_data_len); spi_os_memcpy(data_header + pre_data_len, queue_info->buffer, SPI_DATA_INNER_LENGTH_SIZE - pre_data_len); spi_os_memcpy(&length, data_header, SPI_DATA_INNER_LENGTH_SIZE); } else { /* maximum > head + pos_len */ spi_os_memcpy(&length, (queue_info->buffer + queue->head + SPI_DATA_BOF_SIZE), SPI_DATA_INNER_LENGTH_SIZE); } } length += SPI_DATA_BOF_SIZE + SPI_DATA_EOF_SIZE; buf_length = length + SPI_DATA_MUX_SIZE + SPI_DATA_LENGTH_SIZE; if (length > SPI_DEV_MAX_PACKET_SIZE) { if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info || &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info) { /* IPC Case */ pr_err("%s %s[%x],%s[%u],%s[%u],%s[%u]\n", "[SPI] ERROR : spi_data_dequeue: IPC error", "length", length, "buf_size", queue_info->buf_size, "head", queue->head, "tail", queue->tail); } else if ( &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_TX] == queue_info || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX] == queue_info) { /* RAW Case */ pr_err("%s %s[%x],%s[%u],%s[%u],%s[%u]\n", "[SPI] ERROR : spi_data_dequeue: RAW error", "length", length, "buf_size", queue_info->buf_size, "head", queue->head, "tail", queue->tail); } else { /* RFS Case */ pr_err("%s %s[%x],%s[%u],%s[%u],%s[%u]\n", "[SPI] ERROR : spi_data_dequeue: RFS error", "length", length, "buf_size", queue_info->buf_size, "head", queue->head, "tail", queue->tail); } spi_os_trace_dump_low("spi_data_dequeue error", queue_info->buffer + queue->head - 1, 16); spi_os_trace_dump_low("spi_data_dequeue error", queue_info->buffer + queue->tail - 1, 16); return -1; } if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_TX] == queue_info || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_TX] == queue_info) { unsigned int templength; spi_os_memcpy((char *) pdata, &queue_info->type, SPI_DATA_MUX_SIZE); pdata += SPI_DATA_MUX_SIZE; templength = length-SPI_DATA_BOF_SIZE-SPI_DATA_EOF_SIZE; spi_os_memcpy((char *) pdata, &templength, SPI_DATA_LENGTH_SIZE); pdata += SPI_DATA_LENGTH_SIZE; } if (queue->tail > queue->head) { if (queue->tail - queue->head < length) { pr_err("%s %s tail[%u], head[%u], length[%u]\n", "[SPI] ERROR : spi_data_dequeue:", "request data length is less than queue`s remain data.", queue->tail, queue->head, length); spi_os_trace_dump_low("spi_data_dequeue error", queue_info->buffer + queue->head - 1, 16); spi_os_trace_dump_low("spi_data_dequeue error", queue_info->buffer + queue->tail - 1, 16); return -1; } } else if (queue->tail < queue->head) { if ((queue_info->buf_size - queue->head + queue->tail) < length) { pr_err("%s %s tail[%u], head[%u], length[%u]\n", "[SPI] ERROR : spi_data_dequeue:", "request data length is less than queue`s remain data.", queue->tail, queue->head, length); spi_os_trace_dump_low("spi_data_dequeue error", queue_info->buffer + queue->head - 1, 16); spi_os_trace_dump_low("spi_data_dequeue error", queue_info->buffer + queue->tail - 1, 16); return -1; } } if (queue_info->buf_size < (queue->head+length)) { /* maximum < head + length */ pre_data_len = queue_info->buf_size - queue->head; spi_os_memcpy((char *)pdata, queue_info->buffer + queue->head, pre_data_len); spi_os_memcpy((char *)pdata + pre_data_len, queue_info->buffer, length - pre_data_len); queue->head = length - pre_data_len; } else if (queue_info->buf_size == (queue->head+length)) { /* maximum = head + length */ spi_os_memcpy((char *)pdata, (queue_info->buffer + queue->head), length); queue->head = 0; } else { /* maximum > head + length */ spi_os_memcpy((char *)pdata, (queue_info->buffer + queue->head), length); queue->head = queue->head + length; } return buf_length; }