1 /*
2  * Copyright 2023, 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 #include "whd_int.h"
19 #include "whd_cdc_bdc.h"
20 #include "whd_events_int.h"
21 #include "cyabs_rtos.h"
22 #include "whd_network_types.h"
23 #include "whd_types_int.h"
24 #include "whd_wlioctl.h"
25 #include "whd_thread_internal.h"
26 #include "whd_buffer_api.h"
27 
28 /******************************************************
29 *        Constants
30 ******************************************************/
31 /******************************************************
32 *             Macros
33 ******************************************************/
34 /* bit map related macros */
35 #define  NBBY  8  /* 8 bits per byte */
36 #define  setbit(a, i)   ( ( (uint8_t *)a )[(int)(i) / (int)(NBBY)] |= (uint8_t)(1 << ( (i) % NBBY ) ) )
37 #define  clrbit(a, i)   ( ( (uint8_t *)a )[(int)(i) / (int)(NBBY)] &= (uint8_t) ~(1 << ( (i) % NBBY ) ) )
38 #define  isset(a, i)    ( ( (const uint8_t *)a )[(int)(i) / (int)(NBBY)]& (1 << ( (i) % NBBY ) ) )
39 #define  isclr(a, i)    ( ( ( (const uint8_t *)a )[(int)(i) / (int)(NBBY)]& (1 << ( (i) % NBBY ) ) ) == 0 )
40 
41 /******************************************************
42 *             Local Structures
43 ******************************************************/
44 
45 /******************************************************
46 *             Static Variables
47 ******************************************************/
48 
49 /******************************************************
50 *             Static Function Prototypes
51 ******************************************************/
52 /* helper function for event messages ext API */
53 static uint8_t *whd_management_alloc_event_msgs_buffer(whd_interface_t ifp, whd_buffer_t *buffer);
54 static uint8_t whd_find_number_of_events(const whd_event_num_t *event_nums);
55 
56 /******************************************************
57 *             Static Functions
58 ******************************************************/
59 
whd_find_number_of_events(const whd_event_num_t * event_nums)60 static uint8_t whd_find_number_of_events(const whd_event_num_t *event_nums)
61 {
62     uint8_t count = 0;
63 
64     while (*event_nums != WLC_E_NONE)
65     {
66         count++;
67         event_nums++;
68 
69         if (count >= WHD_MAX_EVENT_SUBSCRIPTION)
70             return 0;
71     }
72     return count + 1;
73 }
74 
75 /**
76  * Registers locally a handler to receive event callbacks.
77  * Does not notify Wi-Fi about event subscription change.
78  * Can be used to refresh local callbacks (e.g. after deep-sleep)
79  * if Wi-Fi is already notified about them.
80  *
81  * This function registers a callback handler to be notified when
82  * a particular event is received.
83  *
84  * @note : Currently there is a limit to the number of simultaneously
85  *         registered events
86  *
87  * @param ifp                 Pointer to handle instance of whd interface
88  * @param event_nums          An array of event types that is to trigger the handler.
89  *                            The array must be terminated with a WLC_E_NONE event
90  *                            See @ref whd_event_num_t for available events
91  * @param handler_func        A function pointer to the new handler callback,
92  *                            or NULL if callbacks are to be disabled for the given event type
93  * @param handler_user_data   A pointer value which will be passed to the event handler function
94  *                            at the time an event is triggered (NULL is allowed)
95  * @param[out] *event_index   entry where the event handler is registered in the list
96  *
97  * @return WHD result code
98  */
whd_management_set_event_handler_locally(whd_interface_t ifp,const whd_event_num_t * event_nums,whd_event_handler_t handler_func,void * handler_user_data,uint16_t * event_index)99 whd_result_t whd_management_set_event_handler_locally(whd_interface_t ifp, const whd_event_num_t *event_nums,
100                                                       whd_event_handler_t handler_func,
101                                                       void *handler_user_data, uint16_t *event_index)
102 {
103     uint16_t entry = (uint16_t)0xFF;
104     uint16_t i;
105     whd_driver_t whd_driver = ifp->whd_driver;
106     whd_cdc_bdc_info_t *cdc_bdc_info = &whd_driver->cdc_bdc_info;
107     uint8_t num_of_events;
108     num_of_events = whd_find_number_of_events(event_nums);
109 
110     if (num_of_events <= 1)
111     {
112         WPRINT_WHD_ERROR( ("Exceeded the maximum event subscription/no event subscribed\n") );
113         return WHD_UNFINISHED;
114     }
115 
116     /* Find an existing matching entry OR the next empty entry */
117     for (i = 0; i < (uint16_t)WHD_EVENT_HANDLER_LIST_SIZE; i++)
118     {
119         /* Find a matching event list OR the first empty event entry */
120         if (!(memcmp(cdc_bdc_info->whd_event_list[i].events, event_nums,
121                      num_of_events * (sizeof(whd_event_num_t) ) ) ) )
122         {
123             /* Check if all the data already matches */
124             if ( (cdc_bdc_info->whd_event_list[i].handler           == handler_func) &&
125                  (cdc_bdc_info->whd_event_list[i].handler_user_data == handler_user_data) &&
126                  (cdc_bdc_info->whd_event_list[i].ifidx == ifp->ifidx) )
127             {
128                 /* send back the entry where the handler is added */
129                 *event_index = i;
130                 return WHD_SUCCESS;
131             }
132         }
133         else if ( (entry == (uint16_t)0xFF) && (cdc_bdc_info->whd_event_list[i].event_set == WHD_FALSE) )
134         {
135             entry = i;
136         }
137     }
138 
139     /* Check if handler function was provided */
140     if (handler_func != NULL)
141     {
142         /* Check if an empty entry was not found */
143         if (entry == (uint16_t)0xFF)
144         {
145             WPRINT_WHD_DEBUG( ("Out of space in event handlers table - try increasing WHD_EVENT_HANDLER_LIST_SIZE\n") );
146             return WHD_OUT_OF_EVENT_HANDLER_SPACE;
147         }
148 
149         /* Add the new handler in at the free space */
150         memcpy (cdc_bdc_info->whd_event_list[entry].events, event_nums, num_of_events * (sizeof(whd_event_num_t) ) );
151         cdc_bdc_info->whd_event_list[entry].handler           = handler_func;
152         cdc_bdc_info->whd_event_list[entry].handler_user_data = handler_user_data;
153         cdc_bdc_info->whd_event_list[entry].ifidx             = ifp->ifidx;
154         cdc_bdc_info->whd_event_list[entry].event_set         = WHD_TRUE;
155 
156         /* send back the entry where the handler is added */
157         *event_index = entry;
158     }
159     else
160     {
161         WPRINT_WHD_ERROR( ("Event handler callback function is NULL/not provided to register\n") );
162         return WHD_BADARG;
163     }
164 
165     return WHD_SUCCESS;
166 }
167 
168 /* Registers locally a handler to receive error callbacks.
169  * Does not notify Wi-Fi about event subscription change.
170  * Can be used to refresh local callbacks (e.g. after deep-sleep)
171  * if Wi-Fi is already notified about them.
172  *
173  * This function registers a callback handler to be notified when
174  * a particular event is received.
175  *
176  * @note : Currently there is a limit to the number of simultaneously
177  *         registered events
178  *
179  * @param whd_driver          Pointer to handle instance of driver
180  * @param error_nums          An error types that is to trigger the handler.
181  *                            See @ref whd_error_num_t for available events
182  * @param handler_func        A function pointer to the new handler callback,
183  *                            or NULL if callbacks are to be disabled for the given event type
184  * @param handler_user_data   A pointer value which will be passed to the event handler function
185  *                            at the time an event is triggered (NULL is allowed)
186  * @param[out] *error_index   entry where the error handler is registered in the list
187  *
188  * @return WHD result code
189  */
whd_set_error_handler_locally(whd_driver_t whd_driver,const uint8_t * error_nums,whd_error_handler_t handler_func,void * handler_user_data,uint16_t * error_index)190 whd_result_t whd_set_error_handler_locally(whd_driver_t whd_driver, const uint8_t *error_nums,
191                                            whd_error_handler_t handler_func,
192                                            void *handler_user_data, uint16_t *error_index)
193 {
194     uint16_t entry = (uint16_t)0xFF;
195     uint16_t i;
196     whd_result_t res;
197     whd_error_info_t *error_info = &whd_driver->error_info;
198 
199 
200     /* Find an existing matching entry OR the next empty entry */
201     for (i = 0; i < (uint16_t)WHD_EVENT_HANDLER_LIST_SIZE; i++)
202     {
203         uint8_t events = error_info->whd_event_list[i].events;
204         /* Find a matching event list OR the first empty event entry */
205         if (events & *error_nums)
206         {
207             /* Check if all the data already matches */
208             if (error_info->whd_event_list[i].handler != NULL)
209             {
210                 handler_func = error_info->whd_event_list[i].handler;
211                 handler_user_data = error_info->whd_event_list[i].handler_user_data;
212                 res = cy_rtos_get_semaphore(&error_info->event_list_mutex, CY_RTOS_NEVER_TIMEOUT, WHD_FALSE);
213                 if (res != WHD_SUCCESS)
214                 {
215                     return res;
216                 }
217                 handler_func(whd_driver, error_nums, NULL, handler_user_data);
218                 CHECK_RETURN(cy_rtos_set_semaphore(&error_info->event_list_mutex, WHD_FALSE) );
219                 return WHD_SUCCESS;
220             }
221         }
222         else if ( (entry == (uint16_t)0xFF) && (error_info->whd_event_list[i].event_set == WHD_FALSE) )
223         {
224             entry = i;
225         }
226     }
227     /* Check if handler function was provided */
228     if (handler_func != NULL)
229     {
230         /* Check if an empty entry was not found */
231         if (entry == (uint16_t)0xFF)
232         {
233             WPRINT_WHD_DEBUG( ("Out of space in error handlers table - try increasing WHD_EVENT_HANDLER_LIST_SIZE\n") );
234             return WHD_OUT_OF_EVENT_HANDLER_SPACE;
235         }
236         /* Add the new handler in at the free space */
237         error_info->whd_event_list[entry].events            = *error_nums;
238         error_info->whd_event_list[entry].handler           = handler_func;
239         error_info->whd_event_list[entry].handler_user_data = handler_user_data;
240         error_info->whd_event_list[entry].event_set         = WHD_TRUE;
241         /* send back the entry where the handler is added */
242         *error_index = entry;
243     }
244     else
245     {
246         WPRINT_WHD_ERROR( ("Error handler callback function is NULL/not provided to register\n") );
247         return WHD_BADARG;
248     }
249 
250     return WHD_SUCCESS;
251 }
252 
253 /* allocates memory for the needed iovar and returns a pointer to the event mask */
whd_management_alloc_event_msgs_buffer(whd_interface_t ifp,whd_buffer_t * buffer)254 static uint8_t *whd_management_alloc_event_msgs_buffer(whd_interface_t ifp, whd_buffer_t *buffer)
255 {
256     uint16_t i;
257     uint16_t j;
258     whd_bool_t use_extended_evt       = WHD_FALSE;
259     uint32_t max_event                  = 0;
260     eventmsgs_ext_t *eventmsgs_ext_data = NULL;
261     uint32_t *data                      = NULL;
262     whd_driver_t whd_driver = ifp->whd_driver;
263     whd_cdc_bdc_info_t *cdc_bdc_info = &whd_driver->cdc_bdc_info;
264 
265     /* Check to see if event that's set requires more than 128 bit */
266     for (i = 0; i < (uint16_t)WHD_EVENT_HANDLER_LIST_SIZE; i++)
267     {
268         if (cdc_bdc_info->whd_event_list[i].event_set)
269         {
270             for (j = 0; cdc_bdc_info->whd_event_list[i].events[j] != WLC_E_NONE; j++)
271             {
272                 uint32_t event_value = cdc_bdc_info->whd_event_list[i].events[j];
273                 if (event_value > 127)
274                 {
275                     use_extended_evt = WHD_TRUE;
276                     if (event_value > max_event)
277                     {
278                         max_event = event_value;
279                     }
280                     /* keep going to get highest value */
281                 }
282             }
283         }
284     }
285 
286     if (WHD_FALSE == use_extended_evt)
287     {
288         /* use old iovar for backwards compat */
289         data = (uint32_t *)whd_cdc_get_iovar_buffer(whd_driver, buffer, (uint16_t)WL_EVENTING_MASK_LEN + 4,
290                                                     "bsscfg:" IOVAR_STR_EVENT_MSGS);
291 
292         if (NULL == data)
293         {
294             return NULL;
295         }
296 
297         data[0] = ifp->bsscfgidx;
298 
299         return (uint8_t *)&data[1];
300     }
301     else
302     {
303         uint8_t mask_len   = (uint8_t)( (max_event + 8) / 8 );
304         data =
305             (uint32_t *)whd_cdc_get_iovar_buffer(whd_driver, buffer,
306                                                  (uint16_t)(sizeof(eventmsgs_ext_t) + mask_len + 4),
307                                                  "bsscfg:" IOVAR_STR_EVENT_MSGS_EXT);
308 
309         if (NULL == data)
310         {
311             return NULL;
312         }
313 
314         data[0] = ifp->bsscfgidx;
315 
316         eventmsgs_ext_data = (eventmsgs_ext_t *)&data[1];
317 
318         memset(eventmsgs_ext_data, 0, sizeof(*eventmsgs_ext_data) );
319         eventmsgs_ext_data->ver     = EVENTMSGS_VER;
320         eventmsgs_ext_data->command = EVENTMSGS_SET_MASK;
321         eventmsgs_ext_data->len     = mask_len;
322         return eventmsgs_ext_data->mask;
323     }
324 }
325 
326 /**
327  * Registers a handler to receive event callbacks.
328  * Subscribe locally and notify Wi-Fi about subscription.
329  *
330  * This function registers a callback handler to be notified when
331  * a particular event is received.
332  *
333  * @note : Currently there is a limit to the number of simultaneously
334  *         registered events
335  *
336  * @param ifp                 Pointer to handle instance of whd interface
337  * @param event_nums          An array of event types that is to trigger the handler.
338  *                            The array must be terminated with a WLC_E_NONE event
339  *                            See @ref whd_event_num_t for available events
340  * @param handler_func        A function pointer to the new handler callback
341  * @param handler_user_data   A pointer value which will be passed to the event handler function
342  *                            at the time an event is triggered (NULL is allowed)
343  * @param[out] *event_index   entry where the event handler is registered in the list
344  *
345  * @return WHD result code
346  */
whd_management_set_event_handler(whd_interface_t ifp,const whd_event_num_t * event_nums,whd_event_handler_t handler_func,void * handler_user_data,uint16_t * event_index)347 whd_result_t whd_management_set_event_handler(whd_interface_t ifp, const whd_event_num_t *event_nums,
348                                               whd_event_handler_t handler_func,
349                                               void *handler_user_data, uint16_t *event_index)
350 {
351     whd_buffer_t buffer;
352     uint8_t *event_mask;
353     uint16_t i;
354     uint16_t j;
355     whd_result_t res;
356     whd_driver_t whd_driver;
357     whd_cdc_bdc_info_t *cdc_bdc_info;
358     whd_interface_t prim_ifp;
359 
360     if (ifp == NULL)
361     {
362         return WHD_UNKNOWN_INTERFACE;
363     }
364 
365     if (!event_nums || !event_index)
366     {
367         WPRINT_WHD_ERROR( ("Event list to be registered is NULL/Event index is NULL") );
368         return WHD_BADARG;
369     }
370 
371     whd_driver = ifp->whd_driver;
372     cdc_bdc_info = &whd_driver->cdc_bdc_info;
373     prim_ifp = whd_get_primary_interface(whd_driver);
374 
375     if (prim_ifp == NULL)
376     {
377         return WHD_UNKNOWN_INTERFACE;
378     }
379 
380     /* Acquire mutex preventing multiple threads accessing the handler at the same time */
381     res = cy_rtos_get_semaphore(&cdc_bdc_info->event_list_mutex, CY_RTOS_NEVER_TIMEOUT, WHD_FALSE);
382     if (res != WHD_SUCCESS)
383     {
384         return res;
385     }
386 
387     /* Set event handler locally  */
388     res = whd_management_set_event_handler_locally(ifp, event_nums, handler_func, handler_user_data, event_index);
389     if (res != WHD_SUCCESS)
390     {
391         WPRINT_WHD_ERROR( ("Error in setting event handler locally, %s failed at %d \n", __func__, __LINE__) );
392         goto set_event_handler_exit;
393     }
394 
395     /* Send the new event mask value to the wifi chip */
396     event_mask = whd_management_alloc_event_msgs_buffer(ifp, &buffer);
397 
398     if (NULL == event_mask)
399     {
400         res = WHD_BUFFER_UNAVAILABLE_PERMANENT;
401         WPRINT_WHD_ERROR( ("Buffer unavailable permanently, %s failed at %d \n", __func__, __LINE__) );
402         goto set_event_handler_exit;
403     }
404 
405     /* Keep the wlan awake while we set the event_msgs */
406     WHD_WLAN_KEEP_AWAKE(whd_driver);
407 
408     /* Set the event bits for each event from every handler */
409     memset(event_mask, 0, (size_t)WL_EVENTING_MASK_LEN);
410     for (i = 0; i < (uint16_t)WHD_EVENT_HANDLER_LIST_SIZE; i++)
411     {
412         if (cdc_bdc_info->whd_event_list[i].event_set)
413         {
414             for (j = 0; cdc_bdc_info->whd_event_list[i].events[j] != WLC_E_NONE; j++)
415             {
416                 setbit(event_mask, cdc_bdc_info->whd_event_list[i].events[j]);
417             }
418         }
419     }
420 
421     res = whd_cdc_send_iovar(prim_ifp, CDC_SET, buffer, 0);
422     if (res != WHD_SUCCESS)
423     {
424         WPRINT_WHD_ERROR( ("%s: send event_msgs(iovar) failed\n", __func__) );
425     }
426 
427     /* set the event_list_mutex here after sending iovar.
428      * we get event_list_mutex -> ioctl_mutex, make sure we didn't have any thread, having ioctl_mutex -> event_list_mutex path.
429      * Otherwise it may cause deadlock
430      */
431     CHECK_RETURN(cy_rtos_set_semaphore(&cdc_bdc_info->event_list_mutex, WHD_FALSE) );
432 
433     /* The wlan chip can sleep from now on */
434     WHD_WLAN_LET_SLEEP(whd_driver);
435     return WHD_SUCCESS;
436 
437 set_event_handler_exit:
438     CHECK_RETURN(cy_rtos_set_semaphore(&cdc_bdc_info->event_list_mutex, WHD_FALSE) );
439     return res;
440 }
441 
whd_wifi_set_event_handler(whd_interface_t ifp,const uint32_t * event_type,whd_event_handler_t handler_func,void * handler_user_data,uint16_t * event_index)442 whd_result_t whd_wifi_set_event_handler(whd_interface_t ifp, const uint32_t *event_type,
443                                         whd_event_handler_t handler_func,
444                                         void *handler_user_data, uint16_t *event_index)
445 {
446     whd_buffer_t buffer;
447     uint8_t *event_mask;
448     uint16_t i;
449     uint16_t j;
450     whd_result_t res;
451     whd_driver_t whd_driver;
452     whd_cdc_bdc_info_t *cdc_bdc_info;
453     whd_interface_t prim_ifp;
454 
455     if (ifp == NULL)
456     {
457         return WHD_UNKNOWN_INTERFACE;
458     }
459 
460     if (!event_type || !event_index)
461     {
462         WPRINT_WHD_ERROR( ("Event list to be registered is NULL/Event index is NULL") );
463         return WHD_BADARG;
464     }
465 
466     whd_driver = ifp->whd_driver;
467     cdc_bdc_info = &whd_driver->cdc_bdc_info;
468     prim_ifp = whd_get_primary_interface(whd_driver);
469 
470     if (prim_ifp == NULL)
471     {
472         return WHD_UNKNOWN_INTERFACE;
473     }
474 
475     /* Acquire mutex preventing multiple threads accessing the handler at the same time */
476     res = cy_rtos_get_semaphore(&cdc_bdc_info->event_list_mutex, CY_RTOS_NEVER_TIMEOUT, WHD_FALSE);
477     if (res != WHD_SUCCESS)
478     {
479         return res;
480     }
481 
482     /* Set event handler locally  */
483     res = whd_management_set_event_handler_locally(ifp, (whd_event_num_t *)event_type, handler_func, handler_user_data,
484                                                    event_index);
485     if (res != WHD_SUCCESS)
486     {
487         WPRINT_WHD_ERROR( ("Error in setting event handler locally, %s failed at %d \n", __func__, __LINE__) );
488         goto set_event_handler_exit;
489     }
490 
491     /* Send the new event mask value to the wifi chip */
492     event_mask = whd_management_alloc_event_msgs_buffer(ifp, &buffer);
493 
494     if (NULL == event_mask)
495     {
496         res = WHD_BUFFER_UNAVAILABLE_PERMANENT;
497         WPRINT_WHD_ERROR( ("Buffer unavailable permanently, %s failed at %d \n", __func__, __LINE__) );
498         goto set_event_handler_exit;
499     }
500 
501     /* Keep the wlan awake while we set the event_msgs */
502     WHD_WLAN_KEEP_AWAKE(whd_driver);
503 
504     /* Set the event bits for each event from every handler */
505     memset(event_mask, 0, (size_t)WL_EVENTING_MASK_LEN);
506     for (i = 0; i < (uint16_t)WHD_EVENT_HANDLER_LIST_SIZE; i++)
507     {
508         if (cdc_bdc_info->whd_event_list[i].event_set)
509         {
510             for (j = 0; cdc_bdc_info->whd_event_list[i].events[j] != WLC_E_NONE; j++)
511             {
512                 setbit(event_mask, cdc_bdc_info->whd_event_list[i].events[j]);
513             }
514         }
515     }
516 
517     res = whd_cdc_send_iovar(prim_ifp, CDC_SET, buffer, 0);
518     if (res != WHD_SUCCESS)
519     {
520         WPRINT_WHD_ERROR( ("%s: send event_msgs(iovar) failed\n", __func__) );
521     }
522 
523     /* set the event_list_mutex here after sending iovar.
524      * we get event_list_mutex -> ioctl_mutex, make sure we didn't have any thread, having ioctl_mutex -> event_list_mutex path.
525      * Otherwise it may cause deadlock
526      */
527     CHECK_RETURN(cy_rtos_set_semaphore(&cdc_bdc_info->event_list_mutex, WHD_FALSE) );
528 
529     /* The wlan chip can sleep from now on */
530     WHD_WLAN_LET_SLEEP(whd_driver);
531     return WHD_SUCCESS;
532 
533 set_event_handler_exit:
534     CHECK_RETURN(cy_rtos_set_semaphore(&cdc_bdc_info->event_list_mutex, WHD_FALSE) );
535     return res;
536 }
537 
538 /**
539  * Registers a handler to receive error callbacks.
540  * Subscribe locally and notify Wi-Fi about subscription.
541  *
542  * This function registers a callback handler to be notified when
543  * a particular event is received.
544  *
545  * @note : Currently there is a limit to the number of simultaneously
546  *         registered events
547  *
548  * @param ifp                 Pointer to handle instance of whd interface
549  * @param event_nums          An numbers of event type that is to trigger the handler.
550  *                            See @ref whd_error_num_t for available events
551  * @param handler_func        A function pointer to the new handler callback
552  * @param handler_user_data   A pointer value which will be passed to the event handler function
553  *                            at the time an event is triggered (NULL is allowed)
554  * @param[out] *error_index   entry where the error handler is registered in the list
555  *
556  * @return WHD result code
557  */
whd_wifi_set_error_handler(whd_interface_t ifp,const uint8_t * error_nums,whd_error_handler_t handler_func,void * handler_user_data,uint16_t * error_index)558 whd_result_t whd_wifi_set_error_handler(whd_interface_t ifp, const uint8_t *error_nums,
559                                         whd_error_handler_t handler_func,
560                                         void *handler_user_data, uint16_t *error_index)
561 {
562     whd_result_t res;
563     whd_driver_t whd_driver;
564     whd_interface_t prim_ifp;
565     if (ifp == NULL)
566     {
567         return WHD_UNKNOWN_INTERFACE;
568     }
569 
570     if (!error_nums || !error_index)
571     {
572         WPRINT_WHD_ERROR( ("Error list to be registered is NULL/Error index is NULL \n") );
573         return WHD_BADARG;
574     }
575 
576     whd_driver = ifp->whd_driver;
577     prim_ifp = whd_get_primary_interface(whd_driver);
578     if (prim_ifp == NULL)
579     {
580         return WHD_UNKNOWN_INTERFACE;
581     }
582 
583     /* Set event handler locally  */
584     res = whd_set_error_handler_locally(whd_driver, error_nums, handler_func, handler_user_data,
585                                         error_index);
586     if (res != WHD_SUCCESS)
587     {
588         WPRINT_WHD_ERROR( ("Error in setting event handler locally, %s failed at %d \n", __func__, __LINE__) );
589         return res;
590     }
591 
592 
593     return WHD_SUCCESS;
594 
595 }
596 
whd_wifi_deregister_event_handler(whd_interface_t ifp,uint16_t event_index)597 uint32_t whd_wifi_deregister_event_handler(whd_interface_t ifp, uint16_t event_index)
598 {
599     whd_driver_t whd_driver;
600     whd_cdc_bdc_info_t *cdc_bdc_info;
601 
602     if (ifp == NULL)
603     {
604         return WHD_UNKNOWN_INTERFACE;
605     }
606 
607     whd_driver = ifp->whd_driver;
608     cdc_bdc_info = &whd_driver->cdc_bdc_info;
609 
610     if (event_index < WHD_EVENT_HANDLER_LIST_SIZE)
611     {
612         memset(cdc_bdc_info->whd_event_list[event_index].events, 0xFF,
613                (sizeof(cdc_bdc_info->whd_event_list[event_index].events) ) );
614         cdc_bdc_info->whd_event_list[event_index].handler = NULL;
615         cdc_bdc_info->whd_event_list[event_index].handler_user_data = NULL;
616         cdc_bdc_info->whd_event_list[event_index].event_set = WHD_FALSE;
617         return WHD_SUCCESS;
618     }
619     if (event_index == 0xFF)
620     {
621         WPRINT_WHD_INFO( ("Event handler not registered \n") );
622         return WHD_SUCCESS;
623     }
624     WPRINT_WHD_DEBUG( ("Invalid event index received to deregister the event handler \n") );
625     return WHD_BADARG;
626 }
627 
whd_wifi_deregister_error_handler(whd_interface_t ifp,uint16_t error_index)628 uint32_t whd_wifi_deregister_error_handler(whd_interface_t ifp, uint16_t error_index)
629 {
630     whd_driver_t whd_driver;
631     whd_error_info_t *error_info;
632 
633     if (ifp == NULL)
634     {
635         return WHD_UNKNOWN_INTERFACE;
636     }
637 
638     whd_driver = ifp->whd_driver;
639     error_info = &whd_driver->error_info;
640 
641     if (error_index < WHD_EVENT_HANDLER_LIST_SIZE)
642     {
643         error_info->whd_event_list[error_index].events  = 0;
644         error_info->whd_event_list[error_index].handler = NULL;
645         error_info->whd_event_list[error_index].handler_user_data = NULL;
646         error_info->whd_event_list[error_index].event_set = WHD_FALSE;
647         return WHD_SUCCESS;
648     }
649     if (error_index == 0xFF)
650     {
651         WPRINT_WHD_INFO( ("Error handler not registered \n") );
652         return WHD_SUCCESS;
653     }
654     WPRINT_WHD_DEBUG( ("Invalid error index received to deregister the event handler \n") );
655     return WHD_BADARG;
656 }
657 
658