Merge tag 'v4.4-rc1'
[firefly-linux-kernel-4.4.55.git] / drivers / cmmb / siano / smsspicommon.c
1 /****************************************************************
2
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2008, Uri Shkolnik
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
11
12  This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 ****************************************************************/
21 #include "smsspicommon.h"
22 #include "smsdbg_prn.h"
23 #include "smscoreapi.h"
24
25 extern volatile bool g_libdownload;
26
27
28 static struct _rx_buffer_st *smsspi_handle_unused_bytes_buf(
29                 struct _spi_dev *dev,
30                 struct _rx_buffer_st *buf, int offset, int len,
31                 int unused_bytes)
32 {
33         struct _rx_buffer_st *tmp_buf;
34
35
36         tmp_buf = dev->cb.allocate_rx_buf(dev->context,
37                 RX_PACKET_SIZE);
38
39
40         if (!tmp_buf) {
41                 sms_err("Failed to allocate RX buffer.\n");
42                 return NULL;
43         }
44         if (unused_bytes > 0) {
45                 /* Copy the remaining bytes to the end of
46                 alignment block (256 bytes) so next read
47                 will be aligned. */
48                 int align_block =
49                         (((unused_bytes + SPI_PACKET_SIZE -
50                         1) >> SPI_PACKET_SIZE_BITS) <<
51                         SPI_PACKET_SIZE_BITS);
52                 memset(tmp_buf->ptr, 0,
53                         align_block - unused_bytes);
54                 memcpy((char *)tmp_buf->ptr +
55                         (align_block - unused_bytes),
56                         (char *)buf->ptr + offset + len -
57                         unused_bytes, unused_bytes);
58         }
59         //sms_info("smsspi_handle_unused_bytes_buf unused_bytes=0x%x offset=0x%x len=0x%x \n",unused_bytes,offset,len);
60         return tmp_buf;
61 }
62
63 static struct _rx_buffer_st *smsspi_common_find_msg(struct _spi_dev *dev,
64                 struct _rx_buffer_st *buf, int offset, int len,
65                 int *unused_bytes, int *missing_bytes)
66 {
67         int i;
68         int recieved_bytes, padded_msg_len;
69         int align_fix;
70         int msg_offset;
71         unsigned char *ptr = (unsigned char *)buf->ptr + offset;
72         if (unused_bytes == NULL || missing_bytes == NULL)
73                 return NULL;
74
75         *missing_bytes = 0;
76         *unused_bytes = 0;
77
78         //sms_info("entering with %d bytes.\n", len);
79         for (i = 0; i < len; i++, ptr++) {
80                 switch (dev->rxState) {
81                 case RxsWait_a5:
82                         dev->rxState =
83                             ((*ptr & 0xff) == 0xa5) ? RxsWait_5a : RxsWait_a5;
84                         dev->rxPacket.msg_offset =
85                             (unsigned long)ptr - (unsigned long)buf->ptr + 4;
86                         break;
87                 case RxsWait_5a:
88                         if ((*ptr & 0xff) == 0x5a) {
89                                 dev->rxState = RxsWait_e7;
90                         }
91                         else {
92                                 dev->rxState = RxsWait_a5;
93                                 i--;
94                                 ptr--;  // re-scan current byte
95                         }
96                         //sms_info("state %d.\n", dev->rxState);
97                         break;
98                 case RxsWait_e7:
99                         if ((*ptr & 0xff) == 0xe7) {
100                                 dev->rxState = RxsWait_7e;
101                         }
102                         else {
103                                 dev->rxState = RxsWait_a5;
104                                 i--;
105                                 ptr--;  // re-scan current byte
106                         }
107                         //sms_info("state %d.\n", dev->rxState);
108                         break;
109                 case RxsWait_7e:
110                         if ((*ptr & 0xff) == 0x7e) {
111                                 dev->rxState = RxsTypeH;
112                         }
113                         else {
114                                 dev->rxState = RxsWait_a5;
115                                 i--;
116                                 ptr--;  // re-scan current byte
117                         }
118                         //sms_info("state %d.\n", dev->rxState);
119                         break;
120                 case RxsTypeH:
121                         dev->rxPacket.msg_buf = buf;
122                         dev->rxPacket.msg_offset =
123                             (unsigned long)ptr - (unsigned long)buf->ptr;
124                         dev->rxState = RxsTypeL;
125                         //sms_info("state %d.\n", dev->rxState);
126                         break;
127                 case RxsTypeL:
128                         dev->rxState = RxsGetSrcId;
129                         //sms_info("state %d.\n", dev->rxState);
130                         break;
131                 case RxsGetSrcId:
132                         dev->rxState = RxsGetDstId;
133                         //sms_info("state %d.\n", dev->rxState);
134                         break;
135                 case RxsGetDstId:
136                         dev->rxState = RxsGetLenL;
137                         //sms_info("state %d.\n", dev->rxState);
138                         break;
139                 case RxsGetLenL:
140                         dev->rxState = RxsGetLenH;
141                         dev->rxPacket.msg_len = (*ptr & 0xff);
142                         //sms_info("state %d.\n", dev->rxState);
143                         break;
144                 case RxsGetLenH:
145                         dev->rxState = RxsFlagsL;
146                         dev->rxPacket.msg_len += (*ptr & 0xff) << 8;
147                         //sms_info("state %d.\n", dev->rxState);
148                         break;
149                 case RxsFlagsL:
150                         dev->rxState = RxsFlagsH;
151                         dev->rxPacket.msg_flags = (*ptr & 0xff);
152                         //sms_info("state %d.\n", dev->rxState);
153                         break;
154                 case RxsFlagsH:
155                         dev->rxState = RxsData;
156                         dev->rxPacket.msg_flags += (*ptr & 0xff) << 8;
157                         //sms_info("state %d.\n", dev->rxState);
158                         break;
159                 case RxsData:
160                         recieved_bytes =
161                             len + offset - dev->rxPacket.msg_offset;
162                         padded_msg_len =
163                             ((dev->rxPacket.msg_len + 4 + SPI_PACKET_SIZE -
164                               1) >> SPI_PACKET_SIZE_BITS) <<
165                             SPI_PACKET_SIZE_BITS;
166                         if (recieved_bytes < padded_msg_len) {
167                                 *unused_bytes = 0;
168                                 *missing_bytes = padded_msg_len -
169                                                 recieved_bytes;
170
171
172                                 return buf;
173                         }
174                         dev->rxState = RxsWait_a5;
175                         if (dev->cb.msg_found_cb) {
176                                 align_fix = 0;
177                                 if (dev->rxPacket.
178                                     msg_flags & MSG_HDR_FLAG_SPLIT_MSG_HDR) {
179                                         align_fix =
180                                             (dev->rxPacket.
181                                              msg_flags >> 8) & 0x3;
182                                         /* The FW aligned the message data
183                                         therefore - alignment bytes should be
184                                         thrown away. Throw the alignment bytes
185                                         by moving the header ahead over the
186                                         alignment bytes. */
187                                         if (align_fix) {
188                                                 int length;
189                                                 ptr =
190                                                     (unsigned char *)dev->rxPacket.
191                                                     msg_buf->ptr +
192                                                     dev->rxPacket.msg_offset;
193
194                                                 /* Restore header to original
195                                                 state before alignment changes
196                                                 */
197                                                 length =
198                                                     (ptr[5] << 8) | ptr[4];
199                                                 length -= align_fix;
200                                                 ptr[5] = length >> 8;
201                                                 ptr[4] = length & 0xff;
202                                                 /* Zero alignment flags */
203                                                 ptr[7] &= 0xfc;
204
205                                                 for (i = MSG_HDR_LEN - 1;
206                                                      i >= 0; i--) {
207                                                         ptr[i + align_fix] =
208                                                             ptr[i];
209                                                 }
210                                                 dev->rxPacket.msg_offset +=
211                                                     align_fix;
212                                         }
213                                 }
214
215                                 sms_info("Msg found and sent to callback func.\n");
216
217                                 /* force all messages to start on
218                                  * 4-byte boundary */
219                                 msg_offset = dev->rxPacket.msg_offset;
220                                 if (msg_offset & 0x3) {
221                                         msg_offset &= (~0x3);
222                                         memmove((unsigned char *)
223                                                 (dev->rxPacket.msg_buf->ptr)
224                                                 + msg_offset,
225                                                 (unsigned char *)
226                                                 (dev->rxPacket.msg_buf->ptr)
227                                                 + dev->rxPacket.msg_offset,
228                                                 dev->rxPacket.msg_len -
229                                                 align_fix);
230                                 }
231
232                                 *unused_bytes =
233                                     len + offset - dev->rxPacket.msg_offset -
234                                     dev->rxPacket.msg_len;
235
236                                 /* In any case we got here - unused_bytes
237                                  * should not be 0 Because we want to force
238                                  * reading at least 256 after the end
239                                  of any found message */
240                                 if (*unused_bytes == 0)
241                                         *unused_bytes = -1;
242
243                                 buf = smsspi_handle_unused_bytes_buf(dev, buf,
244                                                 offset, len, *unused_bytes);
245
246
247
248                                 dev->cb.msg_found_cb(dev->context,
249                                                          dev->rxPacket.msg_buf,
250                                                          msg_offset,
251                                                          dev->rxPacket.msg_len -
252                                                          align_fix);
253
254
255                                 *missing_bytes = 0;
256                                 return buf;
257                         } else {
258                                 sms_info("Msg found but no callback. therefore - thrown away.\n");
259                         }
260                         sms_info("state %d.\n", dev->rxState);
261                         break;
262                 }
263         }
264
265         if (dev->rxState == RxsWait_a5) {
266                 *unused_bytes = 0;
267                 *missing_bytes = 0;
268
269                 return buf;
270         } else {
271                 /* Workaround to corner case: if the last byte of the buffer
272                 is "a5" (first byte of the preamble), the host thinks it should
273                 send another 256 bytes.  In case the a5 is the firmware
274                 underflow byte, this will cause an infinite loop, so we check
275                 for this case explicity. */
276                 if (dev->rxState == RxsWait_5a) {
277                         if ((*(ptr - 2) == 0xa5) || (*((unsigned int*)(ptr-4)) == *((unsigned int*)(ptr-8)))) {
278                                 dev->rxState = RxsWait_a5;
279                                 *unused_bytes = 0;
280                                 *missing_bytes = 0;
281
282                                 return buf;
283                         }
284                 }
285
286                 if ((dev->rxState == RxsWait_5a) && (*(ptr - 2) == 0xa5)) {
287                         dev->rxState = RxsWait_a5;
288                         *unused_bytes = 0;
289                         *missing_bytes = 0;
290
291                         return buf;
292                 }
293
294                 if (dev->rxPacket.msg_offset >= (SPI_PACKET_SIZE + 4))
295                         /* adding 4 for the preamble. */
296                 {               /*The packet will be copied to a new buffer
297                                    and rescaned by the state machine */
298                         struct _rx_buffer_st *tmp_buf = buf;
299                         *unused_bytes = dev->rxState - RxsWait_a5;
300                         tmp_buf = smsspi_handle_unused_bytes_buf(dev, buf,
301                                         offset, len, *unused_bytes);
302                         dev->rxState = RxsWait_a5;
303
304                         dev->cb.free_rx_buf(dev->context, buf);
305
306
307                         *missing_bytes = 0;
308                         return tmp_buf;
309                 } else {
310                         /* report missing bytes and continue
311                            with message scan. */
312                         *unused_bytes = 0;
313                         *missing_bytes = SPI_PACKET_SIZE;
314                         return buf;
315                 }
316         }
317 }
318
319 void smsspi_common_transfer_msg(struct _spi_dev *dev, struct _spi_msg *txmsg,
320                                 int padding_allowed)
321 {
322         int len, bytes_to_transfer;
323         unsigned long tx_phy_addr;
324         int missing_bytes, tx_bytes;
325         int offset, unused_bytes;
326         int align_block;
327         char *txbuf;
328         struct _rx_buffer_st *buf, *tmp_buf;
329
330 #if     SIANO_HALFDUPLEX
331         if (txmsg){
332                 tx_bytes = txmsg->len;
333                 if (padding_allowed)
334                         bytes_to_transfer =
335                             (((tx_bytes + SPI_PACKET_SIZE -
336                                1) >> SPI_PACKET_SIZE_BITS) <<
337                              SPI_PACKET_SIZE_BITS);
338                 else
339                         bytes_to_transfer = (((tx_bytes + 3) >> 2) << 2);
340                 txbuf = txmsg->buf;
341                 tx_phy_addr = txmsg->buf_phy_addr;
342                 len = min(bytes_to_transfer, RX_PACKET_SIZE);
343                 dev->cb.transfer_data_cb(dev->phy_context,(unsigned char *)txbuf,tx_phy_addr,NULL,NULL,len);
344         } else
345 #endif
346
347         {
348         
349 //      sms_info("g_libdownload == %d!!!!!!!!!!!!!!!!!\n",g_libdownload);
350         if(g_libdownload == false)
351                 {
352 //              sms_info("g_libdownload == false!!!!!!!!!!!!!!!!!\n");
353         len = 0;
354         if (!dev->cb.transfer_data_cb) {
355                 sms_err("function called while module is not initialized.\n");
356                 return;
357         }
358         if (txmsg == 0) {
359                 bytes_to_transfer = SPI_PACKET_SIZE;
360                 txbuf = 0;
361                 tx_phy_addr = 0;
362                 tx_bytes = 0;
363         } else {
364                 tx_bytes = txmsg->len;
365                 if (padding_allowed)
366                         bytes_to_transfer =
367                             (((tx_bytes + SPI_PACKET_SIZE -
368                                1) >> SPI_PACKET_SIZE_BITS) <<
369                              SPI_PACKET_SIZE_BITS);
370                 else
371                         bytes_to_transfer = (((tx_bytes + 3) >> 2) << 2);
372                 txbuf = txmsg->buf;
373                 tx_phy_addr = txmsg->buf_phy_addr;
374         }
375         offset = 0;
376         unused_bytes = 0;
377
378         buf =
379             dev->cb.allocate_rx_buf(dev->context,
380                                     RX_PACKET_SIZE + SPI_PACKET_SIZE);
381
382
383         if (!buf) {
384                 sms_err("Failed to allocate RX buffer.\n");
385                 return;
386         }
387         while (bytes_to_transfer || unused_bytes) {
388                 if ((unused_bytes <= 0) && (bytes_to_transfer > 0)) {
389                         len = min(bytes_to_transfer, RX_PACKET_SIZE);
390                         //sms_info("transfering block of %d bytes\n", len);
391                         dev->cb.transfer_data_cb(dev->phy_context,
392                                         (unsigned char *)txbuf,
393                                         tx_phy_addr,
394                                         (unsigned char *)buf->ptr + offset,
395                                         buf->phy_addr + offset, len);
396                 }
397
398                 tmp_buf =
399                     smsspi_common_find_msg(dev, buf, offset, len,
400                                            &unused_bytes, &missing_bytes);
401
402
403                 //sms_info("smsspi_common_transfer_msg unused_bytes=0x%x missing_bytes=0x%x\n", unused_bytes, missing_bytes);
404
405                 if (bytes_to_transfer)
406                         bytes_to_transfer -= len;
407
408                 if (tx_bytes)
409                         tx_bytes -= len;
410
411                 if (missing_bytes)
412                         offset += len;
413
414                 if (unused_bytes) {
415                         /* In this case tmp_buf is a new buffer allocated
416                          * in smsspi_common_find_msg
417                          * and it already contains the unused bytes */
418                         if (unused_bytes > 0) {
419                                 align_block =
420                                     (((unused_bytes + SPI_PACKET_SIZE -
421                                        1) >> SPI_PACKET_SIZE_BITS) <<
422                                      SPI_PACKET_SIZE_BITS);
423                                 len = align_block;
424                         }
425                         offset = 0;
426                         buf = tmp_buf;
427
428                 }
429                 if (tx_bytes <= 0) {
430                         txbuf = 0;
431                         tx_bytes = 0;
432                 }
433                 if (bytes_to_transfer < missing_bytes) {
434                         bytes_to_transfer =
435                             (((missing_bytes + SPI_PACKET_SIZE -
436                                1) >> SPI_PACKET_SIZE_BITS) <<
437                              SPI_PACKET_SIZE_BITS);
438                         sms_info("a message was found, adding bytes to transfer, txmsg %d, total %d\n"
439                         , tx_bytes, bytes_to_transfer);
440                 }
441         }
442
443
444         dev->cb.free_rx_buf(dev->context, buf);
445 }
446 }
447
448 }
449
450 int smsspicommon_init(struct _spi_dev *dev, void *context, void *phy_context,
451                       struct _spi_dev_cb_st *cb)
452 {
453         sms_info("entering.\n");
454         if (cb->transfer_data_cb == 0 ||
455             cb->msg_found_cb == 0 ||
456             cb->allocate_rx_buf == 0 || cb->free_rx_buf == 0) {
457                 sms_err("Invalid input parameters of init routine.\n");
458                 return -1;
459         }
460         dev->context = context;
461         dev->phy_context = phy_context;
462         memcpy(&dev->cb, cb, sizeof(struct _spi_dev_cb_st));
463         dev->rxState = RxsWait_a5;
464         sms_info("exiting.\n");
465         return 0;
466 }