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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5fd9c30 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
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 "wmi.h"
39#include "htc.h"
40#include "nic/nic.h"
41#include "ar9271.h"
42
43/** HTC download pipes mapping.
44 *
45 * @param service_id Identification of WMI service.
46 *
47 * @return Number of pipe used for this service.
48 *
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
55/** HTC upload pipes mapping.
56 *
57 * @param service_id Identification of WMI service.
58 *
59 * @return Number of pipe used for this service.
60 *
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;
76 nic_t *nic =
77 nic_get_from_ddf_dev(ieee80211_get_ddf_dev(htc_device->ieee80211_dev));
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
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;
99 }
100
101 vif_msg.index = 0;
102 vif_msg.rts_thres = host2uint16_t_be(HTC_RTS_THRESHOLD);
103
104 wmi_send_command(htc_device, WMI_VAP_CREATE, (uint8_t *) &vif_msg,
105 sizeof(vif_msg), NULL);
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
112 wmi_send_command(htc_device, WMI_NODE_CREATE, (uint8_t *) &sta_msg,
113 sizeof(sta_msg), NULL);
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);
120
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);
124
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
133static void htc_config_frame_header(htc_frame_header_t *header,
134 size_t buffer_size, uint8_t endpoint_id)
135{
136 memset(header, 0, sizeof(htc_frame_header_t));
137
138 header->endpoint_id = endpoint_id;
139 header->payload_length =
140 host2uint16_t_be(buffer_size - sizeof(htc_frame_header_t));
141}
142
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).
148 * @param buffer_size Size of buffer (including HTC frame header).
149 * @param endpoint_id Destination endpoint.
150 *
151 * @return EOK if succeed, negative error code otherwise.
152 *
153 */
154int htc_send_control_message(htc_device_t *htc_device, void *buffer,
155 size_t buffer_size, uint8_t endpoint_id)
156{
157 htc_config_frame_header((htc_frame_header_t *) buffer, buffer_size,
158 endpoint_id);
159
160 ath_t *ath_device = htc_device->ath_device;
161
162 return ath_device->ops->send_ctrl_message(ath_device, buffer,
163 buffer_size);
164}
165
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).
171 * @param buffer_size Size of buffer (including HTC frame header).
172 * @param endpoint_id Destination endpoint.
173 *
174 * @return EOK if succeed, negative error code otherwise.
175 *
176 */
177int htc_send_data_message(htc_device_t *htc_device, void *buffer,
178 size_t buffer_size, uint8_t endpoint_id)
179{
180 htc_config_frame_header((htc_frame_header_t *) buffer, buffer_size,
181 endpoint_id);
182
183 ath_t *ath_device = htc_device->ath_device;
184
185 return ath_device->ops->send_data_message(ath_device, buffer,
186 buffer_size);
187}
188
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.
195 * @param transferred_size Real size of read data.
196 *
197 * @return EOK if succeed, negative error code otherwise.
198 *
199 */
200int htc_read_data_message(htc_device_t *htc_device, void *buffer,
201 size_t buffer_size, size_t *transferred_size)
202{
203 ath_t *ath_device = htc_device->ath_device;
204
205 return ath_device->ops->read_data_message(ath_device, buffer,
206 buffer_size, transferred_size);
207}
208
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.
215 * @param transferred_size Real size of read data.
216 *
217 * @return EOK if succeed, negative error code otherwise.
218 *
219 */
220int htc_read_control_message(htc_device_t *htc_device, void *buffer,
221 size_t buffer_size, size_t *transferred_size)
222{
223 ath_t *ath_device = htc_device->ath_device;
224
225 return ath_device->ops->read_ctrl_message(ath_device, buffer,
226 buffer_size, transferred_size);
227}
228
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 *
239 */
240static int htc_connect_service(htc_device_t *htc_device,
241 wmi_services_t service_id, int *response_endpoint_no)
242{
243 size_t buffer_size = sizeof(htc_frame_header_t) +
244 sizeof(htc_service_msg_t);
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 *)
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);
259 service_message->connection_flags = 0;
260
261 /* Send HTC message. */
262 int rc = htc_send_control_message(htc_device, buffer, buffer_size,
263 htc_device->endpoints.ctrl_endpoint);
264 if (rc != EOK) {
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);
277 if (rc != EOK) {
278 free(buffer);
279 usb_log_error("Failed to receive HTC service connect response. "
280 "Error: %d\n", rc);
281 return rc;
282 }
283
284 htc_service_resp_msg_t *response_message = (htc_service_resp_msg_t *)
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) {
293 *response_endpoint_no = response_message->endpoint_id;
294 rc = EOK;
295 } else {
296 usb_log_error("Failed to connect HTC service. "
297 "Message status: %d\n", response_message->status);
298 rc = EINVAL;
299 }
300
301 free(buffer);
302
303 return rc;
304}
305
306/** HTC credits initialization message.
307 *
308 * @param htc_device HTC device structure.
309 *
310 * @return EOK if succeed, negative error code otherwise.
311 *
312 */
313static int htc_config_credits(htc_device_t *htc_device)
314{
315 size_t buffer_size = sizeof(htc_frame_header_t) +
316 sizeof(htc_config_msg_t);
317 void *buffer = malloc(buffer_size);
318 htc_config_msg_t *config_message = (htc_config_msg_t *)
319 ((void *) buffer + sizeof(htc_frame_header_t));
320
321 config_message->message_id =
322 host2uint16_t_be(HTC_MESSAGE_CONFIG);
323 /* Magic number to initialize device. */
324 config_message->credits = 33;
325 config_message->pipe_id = 1;
326
327 /* Send HTC message. */
328 int rc = htc_send_control_message(htc_device, buffer, buffer_size,
329 htc_device->endpoints.ctrl_endpoint);
330 if (rc != EOK) {
331 free(buffer);
332 usb_log_error("Failed to send HTC config message. "
333 "Error: %d\n", rc);
334 return rc;
335 }
336
337 free(buffer);
338
339 buffer_size = htc_device->ath_device->ctrl_response_length;
340 buffer = malloc(buffer_size);
341
342 /* Check response from device. */
343 rc = htc_read_control_message(htc_device, buffer, buffer_size, NULL);
344 if (rc != EOK) {
345 usb_log_error("Failed to receive HTC config response message. "
346 "Error: %d\n", rc);
347 }
348
349 free(buffer);
350
351 return rc;
352}
353
354/** HTC setup complete confirmation message.
355 *
356 * @param htc_device HTC device structure.
357 *
358 * @return EOK if succeed, negative error code otherwise.
359 *
360 */
361static int htc_complete_setup(htc_device_t *htc_device)
362{
363 size_t buffer_size = sizeof(htc_frame_header_t) +
364 sizeof(htc_setup_complete_msg_t);
365 void *buffer = malloc(buffer_size);
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);
372
373 /* Send HTC message. */
374 int rc = htc_send_control_message(htc_device, buffer, buffer_size,
375 htc_device->endpoints.ctrl_endpoint);
376 if (rc != EOK)
377 usb_log_error("Failed to send HTC setup complete message. "
378 "Error: %d\n", rc);
379
380 free(buffer);
381
382 return rc;
383}
384
385/** Try to fetch ready message from device.
386 *
387 * Checks that firmware was successfully loaded on device side.
388 *
389 * @param htc_device HTC device structure.
390 *
391 * @return EOK if succeed, EINVAL if response error,
392 * negative error code otherwise.
393 *
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);
399
400 /* Read response from device. */
401 int rc = htc_read_control_message(htc_device, buffer, buffer_size,
402 NULL);
403 if (rc != EOK) {
404 free(buffer);
405 usb_log_error("Failed to receive HTC check ready message. "
406 "Error: %d\n", rc);
407 return rc;
408 }
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)
413 rc = EOK;
414 else
415 rc = EINVAL;
416
417 free(buffer);
418
419 return rc;
420}
421
422/** Initialize HTC device structure.
423 *
424 * @param ath_device Atheros WiFi device connected
425 * with this HTC device.
426 * @param htc_device HTC device structure to be initialized.
427 *
428 * @return EOK if succeed, negative error code otherwise.
429 *
430 */
431int htc_device_init(ath_t *ath_device, ieee80211_dev_t *ieee80211_dev,
432 htc_device_t *htc_device)
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
445/** HTC communication initalization.
446 *
447 * @param htc_device HTC device structure.
448 *
449 * @return EOK if succeed, negative error code otherwise.
450 *
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);
456 if (rc != EOK) {
457 usb_log_error("Device is not in ready state after loading "
458 "firmware.\n");
459 return rc;
460 }
461
462 /*
463 * HTC services initialization start.
464 */
465 rc = htc_connect_service(htc_device, WMI_CONTROL_SERVICE,
466 &htc_device->endpoints.wmi_endpoint);
467 if (rc != EOK) {
468 usb_log_error("Error while initalizing WMI service.\n");
469 return rc;
470 }
471
472 rc = htc_connect_service(htc_device, WMI_BEACON_SERVICE,
473 &htc_device->endpoints.beacon_endpoint);
474 if (rc != EOK) {
475 usb_log_error("Error while initalizing beacon service.\n");
476 return rc;
477 }
478
479 rc = htc_connect_service(htc_device, WMI_CAB_SERVICE,
480 &htc_device->endpoints.cab_endpoint);
481 if (rc != EOK) {
482 usb_log_error("Error while initalizing CAB service.\n");
483 return rc;
484 }
485
486 rc = htc_connect_service(htc_device, WMI_UAPSD_SERVICE,
487 &htc_device->endpoints.uapsd_endpoint);
488 if (rc != EOK) {
489 usb_log_error("Error while initalizing UAPSD service.\n");
490 return rc;
491 }
492
493 rc = htc_connect_service(htc_device, WMI_MGMT_SERVICE,
494 &htc_device->endpoints.mgmt_endpoint);
495 if (rc != EOK) {
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);
502 if (rc != EOK) {
503 usb_log_error("Error while initalizing data best effort "
504 "service.\n");
505 return rc;
506 }
507
508 rc = htc_connect_service(htc_device, WMI_DATA_BK_SERVICE,
509 &htc_device->endpoints.data_bk_endpoint);
510 if (rc != EOK) {
511 usb_log_error("Error while initalizing data background "
512 "service.\n");
513 return rc;
514 }
515
516 rc = htc_connect_service(htc_device, WMI_DATA_VIDEO_SERVICE,
517 &htc_device->endpoints.data_video_endpoint);
518 if (rc != EOK) {
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);
525 if (rc != EOK) {
526 usb_log_error("Error while initalizing data voice service.\n");
527 return rc;
528 }
529
530 /*
531 * HTC services initialization end.
532 */
533
534 /* Credits initialization message. */
535 rc = htc_config_credits(htc_device);
536 if (rc != EOK) {
537 usb_log_error("Failed to send HTC config message.\n");
538 return rc;
539 }
540
541 /* HTC setup complete confirmation message. */
542 rc = htc_complete_setup(htc_device);
543 if (rc != EOK) {
544 usb_log_error("Failed to send HTC complete setup message.\n");
545 return rc;
546 }
547
548 usb_log_info("HTC services initialization finished successfully.\n");
549
550 return EOK;
551}
Note: See TracBrowser for help on using the repository browser.