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