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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b3c39690 was 8a64320e, checked in by Martin Decky <martin@…>, 10 years ago

pre-merge coding style cleanup and code review

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