1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
7 #include <linux/bitfield.h>
21 static const struct wilc_cfg_byte g_cfg_byte
[] = {
26 {WID_WOWLAN_TRIGGER
, 0},
30 static const struct wilc_cfg_hword g_cfg_hword
[] = {
34 static const struct wilc_cfg_word g_cfg_word
[] = {
35 {WID_FAILED_COUNT
, 0},
36 {WID_RECEIVED_FRAGMENT_COUNT
, 0},
37 {WID_SUCCESS_FRAME_COUNT
, 0},
38 {WID_GET_INACTIVE_TIME
, 0},
43 static const struct wilc_cfg_str g_cfg_str
[] = {
44 {WID_FIRMWARE_VERSION
, NULL
},
46 {WID_ASSOC_RES_INFO
, NULL
},
50 #define WILC_RESP_MSG_TYPE_CONFIG_REPLY 'R'
51 #define WILC_RESP_MSG_TYPE_STATUS_INFO 'I'
52 #define WILC_RESP_MSG_TYPE_NETWORK_INFO 'N'
53 #define WILC_RESP_MSG_TYPE_SCAN_COMPLETE 'S'
55 /********************************************
57 * Configuration Functions
59 ********************************************/
61 static int wilc_wlan_cfg_set_byte(u8
*frame
, u32 offset
, u16 id
, u8 val8
)
63 if ((offset
+ 4) >= WILC_MAX_CFG_FRAME_SIZE
)
66 put_unaligned_le16(id
, &frame
[offset
]);
67 put_unaligned_le16(1, &frame
[offset
+ 2]);
68 frame
[offset
+ 4] = val8
;
72 static int wilc_wlan_cfg_set_hword(u8
*frame
, u32 offset
, u16 id
, u16 val16
)
74 if ((offset
+ 5) >= WILC_MAX_CFG_FRAME_SIZE
)
77 put_unaligned_le16(id
, &frame
[offset
]);
78 put_unaligned_le16(2, &frame
[offset
+ 2]);
79 put_unaligned_le16(val16
, &frame
[offset
+ 4]);
84 static int wilc_wlan_cfg_set_word(u8
*frame
, u32 offset
, u16 id
, u32 val32
)
86 if ((offset
+ 7) >= WILC_MAX_CFG_FRAME_SIZE
)
89 put_unaligned_le16(id
, &frame
[offset
]);
90 put_unaligned_le16(4, &frame
[offset
+ 2]);
91 put_unaligned_le32(val32
, &frame
[offset
+ 4]);
96 static int wilc_wlan_cfg_set_str(u8
*frame
, u32 offset
, u16 id
, u8
*str
,
99 if ((offset
+ size
+ 4) >= WILC_MAX_CFG_FRAME_SIZE
)
102 put_unaligned_le16(id
, &frame
[offset
]);
103 put_unaligned_le16(size
, &frame
[offset
+ 2]);
104 if (str
&& size
!= 0)
105 memcpy(&frame
[offset
+ 4], str
, size
);
110 static int wilc_wlan_cfg_set_bin(u8
*frame
, u32 offset
, u16 id
, u8
*b
, u32 size
)
115 if ((offset
+ size
+ 5) >= WILC_MAX_CFG_FRAME_SIZE
)
118 put_unaligned_le16(id
, &frame
[offset
]);
119 put_unaligned_le16(size
, &frame
[offset
+ 2]);
121 if ((b
) && size
!= 0) {
122 memcpy(&frame
[offset
+ 4], b
, size
);
123 for (i
= 0; i
< size
; i
++)
124 checksum
+= frame
[offset
+ i
+ 4];
127 frame
[offset
+ size
+ 4] = checksum
;
132 /********************************************
134 * Configuration Response Functions
136 ********************************************/
138 static void wilc_wlan_parse_response_frame(struct wilc
*wl
, u8
*info
, int size
)
142 struct wilc_cfg
*cfg
= &wl
->cfg
;
146 wid
= get_unaligned_le16(info
);
148 switch (FIELD_GET(WILC_WID_TYPE
, wid
)) {
150 while (cfg
->b
[i
].id
!= WID_NIL
&& cfg
->b
[i
].id
!= wid
)
153 if (cfg
->b
[i
].id
== wid
)
154 cfg
->b
[i
].val
= info
[4];
160 while (cfg
->hw
[i
].id
!= WID_NIL
&& cfg
->hw
[i
].id
!= wid
)
163 if (cfg
->hw
[i
].id
== wid
)
164 cfg
->hw
[i
].val
= get_unaligned_le16(&info
[4]);
170 while (cfg
->w
[i
].id
!= WID_NIL
&& cfg
->w
[i
].id
!= wid
)
173 if (cfg
->w
[i
].id
== wid
)
174 cfg
->w
[i
].val
= get_unaligned_le32(&info
[4]);
180 while (cfg
->s
[i
].id
!= WID_NIL
&& cfg
->s
[i
].id
!= wid
)
183 if (cfg
->s
[i
].id
== wid
)
184 memcpy(cfg
->s
[i
].str
, &info
[2],
185 get_unaligned_le16(&info
[2]) + 2);
187 len
= 2 + get_unaligned_le16(&info
[2]);
198 static void wilc_wlan_parse_info_frame(struct wilc
*wl
, u8
*info
)
202 wid
= get_unaligned_le16(info
);
206 if (len
== 1 && wid
== WID_STATUS
) {
209 while (wl
->cfg
.b
[i
].id
!= WID_NIL
&&
210 wl
->cfg
.b
[i
].id
!= wid
)
213 if (wl
->cfg
.b
[i
].id
== wid
)
214 wl
->cfg
.b
[i
].val
= info
[3];
218 /********************************************
220 * Configuration Exported Functions
222 ********************************************/
224 int wilc_wlan_cfg_set_wid(u8
*frame
, u32 offset
, u16 id
, u8
*buf
, int size
)
226 u8 type
= FIELD_GET(WILC_WID_TYPE
, id
);
232 ret
= wilc_wlan_cfg_set_byte(frame
, offset
, id
, *buf
);
237 ret
= wilc_wlan_cfg_set_hword(frame
, offset
, id
,
243 ret
= wilc_wlan_cfg_set_word(frame
, offset
, id
,
248 ret
= wilc_wlan_cfg_set_str(frame
, offset
, id
, buf
, size
);
252 ret
= wilc_wlan_cfg_set_bin(frame
, offset
, id
, buf
, size
);
259 int wilc_wlan_cfg_get_wid(u8
*frame
, u32 offset
, u16 id
)
261 if ((offset
+ 2) >= WILC_MAX_CFG_FRAME_SIZE
)
264 put_unaligned_le16(id
, &frame
[offset
]);
269 int wilc_wlan_cfg_get_val(struct wilc
*wl
, u16 wid
, u8
*buffer
,
272 u8 type
= FIELD_GET(WILC_WID_TYPE
, wid
);
274 struct wilc_cfg
*cfg
= &wl
->cfg
;
277 if (type
== CFG_BYTE_CMD
) {
278 while (cfg
->b
[i
].id
!= WID_NIL
&& cfg
->b
[i
].id
!= wid
)
281 if (cfg
->b
[i
].id
== wid
) {
282 memcpy(buffer
, &cfg
->b
[i
].val
, 1);
285 } else if (type
== CFG_HWORD_CMD
) {
286 while (cfg
->hw
[i
].id
!= WID_NIL
&& cfg
->hw
[i
].id
!= wid
)
289 if (cfg
->hw
[i
].id
== wid
) {
290 memcpy(buffer
, &cfg
->hw
[i
].val
, 2);
293 } else if (type
== CFG_WORD_CMD
) {
294 while (cfg
->w
[i
].id
!= WID_NIL
&& cfg
->w
[i
].id
!= wid
)
297 if (cfg
->w
[i
].id
== wid
) {
298 memcpy(buffer
, &cfg
->w
[i
].val
, 4);
301 } else if (type
== CFG_STR_CMD
) {
302 while (cfg
->s
[i
].id
!= WID_NIL
&& cfg
->s
[i
].id
!= wid
)
305 if (cfg
->s
[i
].id
== wid
) {
306 u16 size
= get_unaligned_le16(cfg
->s
[i
].str
);
308 if (buffer_size
>= size
) {
309 memcpy(buffer
, &cfg
->s
[i
].str
[2], size
);
317 void wilc_wlan_cfg_indicate_rx(struct wilc
*wilc
, u8
*frame
, int size
,
318 struct wilc_cfg_rsp
*rsp
)
324 msg_id
= frame
[1]; /* seq no */
330 case WILC_RESP_MSG_TYPE_CONFIG_REPLY
:
331 wilc_wlan_parse_response_frame(wilc
, frame
, size
);
332 rsp
->type
= WILC_CFG_RSP
;
333 rsp
->seq_no
= msg_id
;
336 case WILC_RESP_MSG_TYPE_STATUS_INFO
:
337 wilc_wlan_parse_info_frame(wilc
, frame
);
338 rsp
->type
= WILC_CFG_RSP_STATUS
;
339 rsp
->seq_no
= msg_id
;
340 /* call host interface info parse as well */
341 wilc_gnrl_async_info_received(wilc
, frame
- 4, size
+ 4);
344 case WILC_RESP_MSG_TYPE_NETWORK_INFO
:
345 wilc_network_info_received(wilc
, frame
- 4, size
+ 4);
348 case WILC_RESP_MSG_TYPE_SCAN_COMPLETE
:
349 wilc_scan_complete_received(wilc
, frame
- 4, size
+ 4);
353 rsp
->seq_no
= msg_id
;
358 int wilc_wlan_cfg_init(struct wilc
*wl
)
360 struct wilc_cfg_str_vals
*str_vals
;
363 wl
->cfg
.b
= kmemdup(g_cfg_byte
, sizeof(g_cfg_byte
), GFP_KERNEL
);
367 wl
->cfg
.hw
= kmemdup(g_cfg_hword
, sizeof(g_cfg_hword
), GFP_KERNEL
);
371 wl
->cfg
.w
= kmemdup(g_cfg_word
, sizeof(g_cfg_word
), GFP_KERNEL
);
375 wl
->cfg
.s
= kmemdup(g_cfg_str
, sizeof(g_cfg_str
), GFP_KERNEL
);
379 str_vals
= kzalloc(sizeof(*str_vals
), GFP_KERNEL
);
383 wl
->cfg
.str_vals
= str_vals
;
384 /* store the string cfg parameters */
385 wl
->cfg
.s
[i
].id
= WID_FIRMWARE_VERSION
;
386 wl
->cfg
.s
[i
].str
= str_vals
->firmware_version
;
388 wl
->cfg
.s
[i
].id
= WID_MAC_ADDR
;
389 wl
->cfg
.s
[i
].str
= str_vals
->mac_address
;
391 wl
->cfg
.s
[i
].id
= WID_ASSOC_RES_INFO
;
392 wl
->cfg
.s
[i
].str
= str_vals
->assoc_rsp
;
394 wl
->cfg
.s
[i
].id
= WID_NIL
;
395 wl
->cfg
.s
[i
].str
= NULL
;
409 void wilc_wlan_cfg_deinit(struct wilc
*wl
)
415 kfree(wl
->cfg
.str_vals
);