1 /*
2  * Copyright 2022, Cypress Semiconductor Corporation (an Infineon company)
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /** @file
19  *  Provides generic clm blob file download functionality
20  */
21 
22 #include <stdlib.h>
23 #include "whd_clm.h"
24 #include "whd_wlioctl.h"
25 #include "whd_cdc_bdc.h"
26 #include "whd_debug.h"
27 #include "whd_int.h"
28 #include "whd_buffer_api.h"
29 #include "whd_resource_if.h"
30 #include "whd_resource_api.h"
31 #include "whd_types_int.h"
32 
33 /******************************************************
34 * @cond       Constants
35 ******************************************************/
36 
37 /*
38    Generic interface for downloading required data onto the dongle
39  */
40 static whd_result_t
whd_download_wifi_clm_image(whd_interface_t ifp,const char * iovar,uint16_t flag,uint16_t dload_type,unsigned char * dload_buf,uint32_t len)41 whd_download_wifi_clm_image(whd_interface_t ifp, const char *iovar, uint16_t flag, uint16_t dload_type,
42                             unsigned char *dload_buf, uint32_t len)
43 {
44     wl_dload_data_t *dload_ptr = (wl_dload_data_t *)dload_buf;
45     uint32_t dload_data_offset;
46     whd_buffer_t buffer;
47     uint8_t *iov_data;
48     whd_driver_t whd_driver = ifp->whd_driver;
49 
50     dload_data_offset = offsetof(wl_dload_data_t, data);
51     dload_ptr->flag = htod16( (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT) | flag );
52     dload_ptr->dload_type = htod16(dload_type);
53     dload_ptr->len = htod32(len - dload_data_offset);
54 
55     dload_ptr->crc = 0;
56 
57     whd_assert("dload buffer too large", len < 0xffffffff - 8);
58     len = len + 8 - (len % 8);
59 
60     iov_data = (uint8_t *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, (uint16_t)len, iovar);
61     CHECK_IOCTL_BUFFER(iov_data);
62     memcpy(iov_data, (uint8_t *)dload_ptr, len);
63     CHECK_RETURN(whd_cdc_send_iovar(ifp, CDC_SET, buffer, NULL) );
64     return WHD_SUCCESS;
65 }
66 
whd_process_clm_data(whd_interface_t ifp)67 whd_result_t whd_process_clm_data(whd_interface_t ifp)
68 {
69     whd_result_t ret = WHD_SUCCESS;
70     uint32_t clm_blob_size;
71     uint32_t size2alloc, data_offset;
72     unsigned char *chunk_buf;
73     uint16_t dl_flag = DL_BEGIN;
74     uint32_t chunk_len;
75     uint32_t size_read;
76     uint8_t *image;
77     uint32_t blocks_count = 0;
78     uint16_t datalen = 0;
79     uint32_t i, j, num_buff;
80     uint32_t transfer_progress;
81     whd_driver_t whd_driver = ifp->whd_driver;
82 
83     /* clm file size is the initial datalen value which is decremented */
84     ret = whd_resource_size(whd_driver, WHD_RESOURCE_WLAN_CLM, &clm_blob_size);
85 
86     if (ret != WHD_SUCCESS)
87     {
88         WPRINT_WHD_ERROR( ("Fatal error: download_resource doesn't exist\n") );
89         return ret;
90     }
91 
92     ret = whd_get_resource_no_of_blocks(whd_driver, WHD_RESOURCE_WLAN_CLM, &blocks_count);
93     if (ret != WHD_SUCCESS)
94     {
95         WPRINT_WHD_ERROR( ("Fatal error: download_resource blocks count not know\n") );
96         return ret;
97     }
98 
99     data_offset = offsetof(wl_dload_data_t, data);
100     size2alloc = data_offset + BLOCK_SIZE;
101 
102 
103     if ( (chunk_buf = (unsigned char *)malloc(size2alloc) ) != NULL )
104     {
105         memset(chunk_buf, 0, size2alloc);
106         transfer_progress = 0;
107         for (i = 0; i < blocks_count; i++)
108         {
109             whd_get_resource_block(whd_driver, WHD_RESOURCE_WLAN_CLM, i, (const uint8_t **)&image, &size_read);
110 
111             num_buff = (size_read + BLOCK_SIZE - 1) / BLOCK_SIZE;
112             if (blocks_count != 1)
113                 transfer_progress = 0;
114 
115             for (j = 0; j < num_buff; j++)
116             {
117                 if (size_read >= BLOCK_SIZE)
118                     chunk_len = BLOCK_SIZE;
119                 else
120                     chunk_len = size_read;
121                 memcpy(chunk_buf + data_offset, &image[transfer_progress], chunk_len);
122 
123                 if (datalen + chunk_len == clm_blob_size)
124                 {
125                     dl_flag |= DL_END;
126                 }
127 
128                 ret = whd_download_wifi_clm_image(ifp, IOVAR_STR_CLMLOAD, dl_flag, DL_TYPE_CLM, chunk_buf,
129                                                   data_offset + chunk_len);
130                 dl_flag &= (uint16_t) ~DL_BEGIN;
131                 transfer_progress += chunk_len;
132                 size_read = size_read - chunk_len;
133                 datalen += chunk_len;
134             }
135         }
136 
137         free(chunk_buf);
138         if (ret != WHD_SUCCESS)
139         {
140             whd_result_t ret_clmload_status;
141             whd_buffer_t buffer;
142             whd_buffer_t response;
143             void *data;
144 
145             WPRINT_WHD_DEBUG( ("clmload (%" PRIu32 " byte file) failed with return %" PRIu32 "; ", clm_blob_size,
146                                ret) );
147             data = (int *)whd_cdc_get_iovar_buffer(whd_driver, &buffer, 4, IOVAR_STR_CLMLOAD_STATUS);
148             CHECK_IOCTL_BUFFER(data);
149             ret_clmload_status = whd_cdc_send_iovar(ifp, CDC_GET, buffer, &response);
150             if (ret_clmload_status != WHD_SUCCESS)
151             {
152                 WPRINT_WHD_DEBUG( ("clmload_status failed with return %lu\n", ret_clmload_status) );
153             }
154             else
155             {
156                 uint8_t *clmload_status = (uint8_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, response);
157                 if (clmload_status != NULL)
158                 {
159                     WPRINT_WHD_DEBUG( ("clmload_status is %d\n", *clmload_status) );
160                     CHECK_RETURN(whd_buffer_release(whd_driver, response, WHD_NETWORK_RX) );
161                 }
162             }
163         }
164     }
165     else
166     {
167         WPRINT_WHD_ERROR( ("Memory allocation failure, %s failed at %d \n", __func__, __LINE__) );
168         ret = WHD_MALLOC_FAILURE;
169     }
170 
171     return ret;
172 }
173