source: mainline/uspace/drv/nic/ar9271/htc.c

Last change on this file was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 15.4 KB
Line 
1/*
2 * Copyright (c) 2014 Jan Kolarik
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file htc.c
30 *
31 * Implementation of Atheros HTC communication.
32 *
33 */
34
35#include <usb/debug.h>
36#include <byteorder.h>
37#include <errno.h>
38#include <str_error.h>
39#include "wmi.h"
40#include "htc.h"
41#include "nic/nic.h"
42#include "ar9271.h"
43
44/** HTC download pipes mapping.
45 *
46 * @param service_id Identification of WMI service.
47 *
48 * @return Number of pipe used for this service.
49 *
50 */
51static inline uint8_t wmi_service_to_download_pipe(wmi_services_t service_id)
52{
53 return (service_id == WMI_CONTROL_SERVICE) ? 3 : 2;
54}
55
56/** HTC upload pipes mapping.
57 *
58 * @param service_id Identification of WMI service.
59 *
60 * @return Number of pipe used for this service.
61 *
62 */
63static inline uint8_t wmi_service_to_upload_pipe(wmi_services_t service_id)
64{
65 return (service_id == WMI_CONTROL_SERVICE) ? 4 : 1;
66}
67
68errno_t htc_init_new_vif(htc_device_t *htc_device)
69{
70 htc_vif_msg_t vif_msg;
71 htc_sta_msg_t sta_msg;
72
73 memset(&vif_msg, 0, sizeof(htc_vif_msg_t));
74 memset(&sta_msg, 0, sizeof(htc_sta_msg_t));
75
76 nic_address_t addr;
77 nic_t *nic =
78 nic_get_from_ddf_dev(ieee80211_get_ddf_dev(htc_device->ieee80211_dev));
79 nic_query_address(nic, &addr);
80
81 memcpy(&vif_msg.addr, &addr.address, ETH_ADDR);
82 memcpy(&sta_msg.addr, &addr.address, ETH_ADDR);
83
84 ieee80211_operating_mode_t op_mode =
85 ieee80211_query_current_op_mode(htc_device->ieee80211_dev);
86
87 switch (op_mode) {
88 case IEEE80211_OPMODE_ADHOC:
89 vif_msg.op_mode = HTC_OPMODE_ADHOC;
90 break;
91 case IEEE80211_OPMODE_AP:
92 vif_msg.op_mode = HTC_OPMODE_AP;
93 break;
94 case IEEE80211_OPMODE_MESH:
95 vif_msg.op_mode = HTC_OPMODE_MESH;
96 break;
97 case IEEE80211_OPMODE_STATION:
98 vif_msg.op_mode = HTC_OPMODE_STATION;
99 break;
100 }
101
102 vif_msg.index = 0;
103 vif_msg.rts_thres = host2uint16_t_be(HTC_RTS_THRESHOLD);
104
105 wmi_send_command(htc_device, WMI_VAP_CREATE, (uint8_t *) &vif_msg,
106 sizeof(vif_msg), NULL);
107
108 sta_msg.is_vif_sta = 1;
109 sta_msg.max_ampdu = host2uint16_t_be(0xFFFF);
110 sta_msg.sta_index = 0;
111 sta_msg.vif_index = 0;
112
113 wmi_send_command(htc_device, WMI_NODE_CREATE, (uint8_t *) &sta_msg,
114 sizeof(sta_msg), NULL);
115
116 /* Write first 4 bytes of MAC address. */
117 uint32_t id0;
118 memcpy(&id0, &addr.address, 4);
119 id0 = host2uint32_t_le(id0);
120 wmi_reg_write(htc_device, AR9271_STATION_ID0, id0);
121
122 /* Write last 2 bytes of MAC address (and preserve existing data). */
123 uint32_t id1;
124 wmi_reg_read(htc_device, AR9271_STATION_ID1, &id1);
125
126 uint16_t id1_addr;
127 memcpy(&id1_addr, &addr.address[4], 2);
128 id1 = (id1 & ~AR9271_STATION_ID1_MASK) | host2uint16_t_le(id1_addr);
129 wmi_reg_write(htc_device, AR9271_STATION_ID1, id1);
130
131 return EOK;
132}
133
134static void htc_config_frame_header(htc_frame_header_t *header,
135 size_t buffer_size, uint8_t endpoint_id)
136{
137 memset(header, 0, sizeof(htc_frame_header_t));
138
139 header->endpoint_id = endpoint_id;
140 header->payload_length =
141 host2uint16_t_be(buffer_size - sizeof(htc_frame_header_t));
142}
143
144/** Send control HTC message to USB device.
145 *
146 * @param htc_device HTC device structure.
147 * @param buffer Buffer with data to be sent to USB device
148 * (without HTC frame header).
149 * @param buffer_size Size of buffer (including HTC frame header).
150 * @param endpoint_id Destination endpoint.
151 *
152 * @return EOK if succeed, error code otherwise.
153 *
154 */
155errno_t htc_send_control_message(htc_device_t *htc_device, void *buffer,
156 size_t buffer_size, uint8_t endpoint_id)
157{
158 htc_config_frame_header((htc_frame_header_t *) buffer, buffer_size,
159 endpoint_id);
160
161 ath_t *ath_device = htc_device->ath_device;
162
163 return ath_device->ops->send_ctrl_message(ath_device, buffer,
164 buffer_size);
165}
166
167/** Send data HTC message to USB device.
168 *
169 * @param htc_device HTC device structure.
170 * @param buffer Buffer with data to be sent to USB device
171 * (without HTC frame header).
172 * @param buffer_size Size of buffer (including HTC frame header).
173 * @param endpoint_id Destination endpoint.
174 *
175 * @return EOK if succeed, error code otherwise.
176 *
177 */
178errno_t htc_send_data_message(htc_device_t *htc_device, void *buffer,
179 size_t buffer_size, uint8_t endpoint_id)
180{
181 htc_config_frame_header((htc_frame_header_t *) buffer, buffer_size,
182 endpoint_id);
183
184 ath_t *ath_device = htc_device->ath_device;
185
186 return ath_device->ops->send_data_message(ath_device, buffer,
187 buffer_size);
188}
189
190/** Read HTC data message from USB device.
191 *
192 * @param htc_device HTC device structure.
193 * @param buffer Buffer where data from USB device
194 * will be stored.
195 * @param buffer_size Size of buffer.
196 * @param transferred_size Real size of read data.
197 *
198 * @return EOK if succeed, error code otherwise.
199 *
200 */
201errno_t htc_read_data_message(htc_device_t *htc_device, void *buffer,
202 size_t buffer_size, size_t *transferred_size)
203{
204 ath_t *ath_device = htc_device->ath_device;
205
206 return ath_device->ops->read_data_message(ath_device, buffer,
207 buffer_size, transferred_size);
208}
209
210/** Read HTC control message from USB device.
211 *
212 * @param htc_device HTC device structure.
213 * @param buffer Buffer where data from USB device
214 * will be stored.
215 * @param buffer_size Size of buffer.
216 * @param transferred_size Real size of read data.
217 *
218 * @return EOK if succeed, error code otherwise.
219 *
220 */
221errno_t htc_read_control_message(htc_device_t *htc_device, void *buffer,
222 size_t buffer_size, size_t *transferred_size)
223{
224 ath_t *ath_device = htc_device->ath_device;
225
226 return ath_device->ops->read_ctrl_message(ath_device, buffer,
227 buffer_size, transferred_size);
228}
229
230/** Initialize HTC service.
231 *
232 * @param htc_device HTC device structure.
233 * @param service_id Identification of WMI service.
234 * @param response_endpoint_no HTC endpoint to be used for
235 * this service.
236 *
237 * @return EOK if succeed, EINVAL when failed to connect service,
238 * error code otherwise.
239 *
240 */
241static errno_t htc_connect_service(htc_device_t *htc_device,
242 wmi_services_t service_id, int *response_endpoint_no)
243{
244 size_t buffer_size = sizeof(htc_frame_header_t) +
245 sizeof(htc_service_msg_t);
246 void *buffer = malloc(buffer_size);
247 memset(buffer, 0, buffer_size);
248
249 /* Fill service message structure. */
250 htc_service_msg_t *service_message = (htc_service_msg_t *)
251 ((void *) buffer + sizeof(htc_frame_header_t));
252 service_message->service_id =
253 host2uint16_t_be(service_id);
254 service_message->message_id =
255 host2uint16_t_be(HTC_MESSAGE_CONNECT_SERVICE);
256 service_message->download_pipe_id =
257 wmi_service_to_download_pipe(service_id);
258 service_message->upload_pipe_id =
259 wmi_service_to_upload_pipe(service_id);
260 service_message->connection_flags = 0;
261
262 /* Send HTC message. */
263 errno_t rc = htc_send_control_message(htc_device, buffer, buffer_size,
264 htc_device->endpoints.ctrl_endpoint);
265 if (rc != EOK) {
266 free(buffer);
267 usb_log_error("Failed to send HTC message. Error: %s\n", str_error_name(rc));
268 return rc;
269 }
270
271 free(buffer);
272
273 buffer_size = htc_device->ath_device->ctrl_response_length;
274 buffer = malloc(buffer_size);
275
276 /* Read response from device. */
277 rc = htc_read_control_message(htc_device, buffer, buffer_size, NULL);
278 if (rc != EOK) {
279 free(buffer);
280 usb_log_error("Failed to receive HTC service connect response. "
281 "Error: %s\n", str_error_name(rc));
282 return rc;
283 }
284
285 htc_service_resp_msg_t *response_message = (htc_service_resp_msg_t *)
286 ((void *) buffer + sizeof(htc_frame_header_t));
287
288 /*
289 * If service was successfully connected,
290 * write down HTC endpoint number that will
291 * be used for communication.
292 */
293 if (response_message->status == HTC_SERVICE_SUCCESS) {
294 *response_endpoint_no = response_message->endpoint_id;
295 rc = EOK;
296 } else {
297 usb_log_error("Failed to connect HTC service. "
298 "Message status: %d\n", response_message->status);
299 rc = EINVAL;
300 }
301
302 free(buffer);
303
304 return rc;
305}
306
307/** HTC credits initialization message.
308 *
309 * @param htc_device HTC device structure.
310 *
311 * @return EOK if succeed, error code otherwise.
312 *
313 */
314static errno_t htc_config_credits(htc_device_t *htc_device)
315{
316 size_t buffer_size = sizeof(htc_frame_header_t) +
317 sizeof(htc_config_msg_t);
318 void *buffer = malloc(buffer_size);
319 htc_config_msg_t *config_message = (htc_config_msg_t *)
320 ((void *) buffer + sizeof(htc_frame_header_t));
321
322 config_message->message_id =
323 host2uint16_t_be(HTC_MESSAGE_CONFIG);
324 /* Magic number to initialize device. */
325 config_message->credits = 33;
326 config_message->pipe_id = 1;
327
328 /* Send HTC message. */
329 errno_t rc = htc_send_control_message(htc_device, buffer, buffer_size,
330 htc_device->endpoints.ctrl_endpoint);
331 if (rc != EOK) {
332 free(buffer);
333 usb_log_error("Failed to send HTC config message. "
334 "Error: %s\n", str_error_name(rc));
335 return rc;
336 }
337
338 free(buffer);
339
340 buffer_size = htc_device->ath_device->ctrl_response_length;
341 buffer = malloc(buffer_size);
342
343 /* Check response from device. */
344 rc = htc_read_control_message(htc_device, buffer, buffer_size, NULL);
345 if (rc != EOK) {
346 usb_log_error("Failed to receive HTC config response message. "
347 "Error: %s\n", str_error_name(rc));
348 }
349
350 free(buffer);
351
352 return rc;
353}
354
355/** HTC setup complete confirmation message.
356 *
357 * @param htc_device HTC device structure.
358 *
359 * @return EOK if succeed, error code otherwise.
360 *
361 */
362static errno_t htc_complete_setup(htc_device_t *htc_device)
363{
364 size_t buffer_size = sizeof(htc_frame_header_t) +
365 sizeof(htc_setup_complete_msg_t);
366 void *buffer = malloc(buffer_size);
367 htc_setup_complete_msg_t *complete_message =
368 (htc_setup_complete_msg_t *)
369 ((void *) buffer + sizeof(htc_frame_header_t));
370
371 complete_message->message_id =
372 host2uint16_t_be(HTC_MESSAGE_SETUP_COMPLETE);
373
374 /* Send HTC message. */
375 errno_t rc = htc_send_control_message(htc_device, buffer, buffer_size,
376 htc_device->endpoints.ctrl_endpoint);
377 if (rc != EOK)
378 usb_log_error("Failed to send HTC setup complete message. "
379 "Error: %s\n", str_error_name(rc));
380
381 free(buffer);
382
383 return rc;
384}
385
386/** Try to fetch ready message from device.
387 *
388 * Checks that firmware was successfully loaded on device side.
389 *
390 * @param htc_device HTC device structure.
391 *
392 * @return EOK if succeed, EINVAL if response error,
393 * error code otherwise.
394 *
395 */
396static errno_t htc_check_ready(htc_device_t *htc_device)
397{
398 size_t buffer_size = htc_device->ath_device->ctrl_response_length;
399 void *buffer = malloc(buffer_size);
400
401 /* Read response from device. */
402 errno_t rc = htc_read_control_message(htc_device, buffer, buffer_size,
403 NULL);
404 if (rc != EOK) {
405 free(buffer);
406 usb_log_error("Failed to receive HTC check ready message. "
407 "Error: %s\n", str_error_name(rc));
408 return rc;
409 }
410
411 uint16_t *message_id = (uint16_t *) ((void *) buffer +
412 sizeof(htc_frame_header_t));
413 if (uint16_t_be2host(*message_id) == HTC_MESSAGE_READY)
414 rc = EOK;
415 else
416 rc = EINVAL;
417
418 free(buffer);
419
420 return rc;
421}
422
423/** Initialize HTC device structure.
424 *
425 * @param ath_device Atheros WiFi device connected
426 * with this HTC device.
427 * @param htc_device HTC device structure to be initialized.
428 *
429 * @return EOK if succeed, error code otherwise.
430 *
431 */
432errno_t htc_device_init(ath_t *ath_device, ieee80211_dev_t *ieee80211_dev,
433 htc_device_t *htc_device)
434{
435 fibril_mutex_initialize(&htc_device->rx_lock);
436 fibril_mutex_initialize(&htc_device->tx_lock);
437
438 htc_device->endpoints.ctrl_endpoint = 0;
439
440 htc_device->ath_device = ath_device;
441 htc_device->ieee80211_dev = ieee80211_dev;
442
443 return EOK;
444}
445
446/** HTC communication initalization.
447 *
448 * @param htc_device HTC device structure.
449 *
450 * @return EOK if succeed, error code otherwise.
451 *
452 */
453errno_t htc_init(htc_device_t *htc_device)
454{
455 /* First check ready message in device. */
456 errno_t rc = htc_check_ready(htc_device);
457 if (rc != EOK) {
458 usb_log_error("Device is not in ready state after loading "
459 "firmware.\n");
460 return rc;
461 }
462
463 /*
464 * HTC services initialization start.
465 */
466 rc = htc_connect_service(htc_device, WMI_CONTROL_SERVICE,
467 &htc_device->endpoints.wmi_endpoint);
468 if (rc != EOK) {
469 usb_log_error("Error while initalizing WMI service.\n");
470 return rc;
471 }
472
473 rc = htc_connect_service(htc_device, WMI_BEACON_SERVICE,
474 &htc_device->endpoints.beacon_endpoint);
475 if (rc != EOK) {
476 usb_log_error("Error while initalizing beacon service.\n");
477 return rc;
478 }
479
480 rc = htc_connect_service(htc_device, WMI_CAB_SERVICE,
481 &htc_device->endpoints.cab_endpoint);
482 if (rc != EOK) {
483 usb_log_error("Error while initalizing CAB service.\n");
484 return rc;
485 }
486
487 rc = htc_connect_service(htc_device, WMI_UAPSD_SERVICE,
488 &htc_device->endpoints.uapsd_endpoint);
489 if (rc != EOK) {
490 usb_log_error("Error while initalizing UAPSD service.\n");
491 return rc;
492 }
493
494 rc = htc_connect_service(htc_device, WMI_MGMT_SERVICE,
495 &htc_device->endpoints.mgmt_endpoint);
496 if (rc != EOK) {
497 usb_log_error("Error while initalizing MGMT service.\n");
498 return rc;
499 }
500
501 rc = htc_connect_service(htc_device, WMI_DATA_BE_SERVICE,
502 &htc_device->endpoints.data_be_endpoint);
503 if (rc != EOK) {
504 usb_log_error("Error while initalizing data best effort "
505 "service.\n");
506 return rc;
507 }
508
509 rc = htc_connect_service(htc_device, WMI_DATA_BK_SERVICE,
510 &htc_device->endpoints.data_bk_endpoint);
511 if (rc != EOK) {
512 usb_log_error("Error while initalizing data background "
513 "service.\n");
514 return rc;
515 }
516
517 rc = htc_connect_service(htc_device, WMI_DATA_VIDEO_SERVICE,
518 &htc_device->endpoints.data_video_endpoint);
519 if (rc != EOK) {
520 usb_log_error("Error while initalizing data video service.\n");
521 return rc;
522 }
523
524 rc = htc_connect_service(htc_device, WMI_DATA_VOICE_SERVICE,
525 &htc_device->endpoints.data_voice_endpoint);
526 if (rc != EOK) {
527 usb_log_error("Error while initalizing data voice service.\n");
528 return rc;
529 }
530
531 /*
532 * HTC services initialization end.
533 */
534
535 /* Credits initialization message. */
536 rc = htc_config_credits(htc_device);
537 if (rc != EOK) {
538 usb_log_error("Failed to send HTC config message.\n");
539 return rc;
540 }
541
542 /* HTC setup complete confirmation message. */
543 rc = htc_complete_setup(htc_device);
544 if (rc != EOK) {
545 usb_log_error("Failed to send HTC complete setup message.\n");
546 return rc;
547 }
548
549 usb_log_info("HTC services initialization finished successfully.\n");
550
551 return EOK;
552}
Note: See TracBrowser for help on using the repository browser.