source: mainline/uspace/drv/nic/ar9271/wmi.c@ eff60ca

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eff60ca was fb1007ef, checked in by Jan Vesely <jano.vesely@…>, 10 years ago

ar9271: Add missing headers

  • Property mode set to 100644
File size: 8.2 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 wmi.c
30 *
31 * Implementation of Atheros WMI communication.
32 *
33 */
34
35#include <usb/debug.h>
[fb1007ef]36#include <errno.h>
[59fa7ab]37#include <malloc.h>
38#include <mem.h>
39#include <byteorder.h>
40#include "wmi.h"
41
[8a64320e]42/** WMI registry read.
43 *
[59fa7ab]44 * @param htc_device HTC device structure.
45 * @param reg_offset Registry offset (address) to be read.
[8a64320e]46 * @param res Stored result.
47 *
[59fa7ab]48 * @return EOK if succeed, negative error code otherwise.
[8a64320e]49 *
[59fa7ab]50 */
51int wmi_reg_read(htc_device_t *htc_device, uint32_t reg_offset, uint32_t *res)
52{
53 uint32_t cmd_value = host2uint32_t_be(reg_offset);
54
[8a64320e]55 void *resp_buffer =
56 malloc(htc_device->ath_device->ctrl_response_length);
[59fa7ab]57
[8a64320e]58 int rc = wmi_send_command(htc_device, WMI_REG_READ,
59 (uint8_t *) &cmd_value, sizeof(cmd_value), resp_buffer);
[59fa7ab]60
[8a64320e]61 if (rc != EOK) {
[59fa7ab]62 usb_log_error("Failed to read registry value.\n");
63 return rc;
64 }
65
[8a64320e]66 uint32_t *resp_value = (uint32_t *) ((void *) resp_buffer +
67 sizeof(htc_frame_header_t) + sizeof(wmi_command_header_t));
[59fa7ab]68
69 *res = uint32_t_be2host(*resp_value);
70
71 return rc;
72}
73
[8a64320e]74/** WMI registry write.
75 *
[59fa7ab]76 * @param htc_device HTC device structure.
77 * @param reg_offset Registry offset (address) to be written.
[8a64320e]78 * @param val Value to be written
79 *
[59fa7ab]80 * @return EOK if succeed, negative error code otherwise.
[8a64320e]81 *
[59fa7ab]82 */
83int wmi_reg_write(htc_device_t *htc_device, uint32_t reg_offset, uint32_t val)
84{
85 uint32_t cmd_buffer[] = {
[8a64320e]86 host2uint32_t_be(reg_offset),
87 host2uint32_t_be(val)
[59fa7ab]88 };
89
[8a64320e]90 void *resp_buffer =
91 malloc(htc_device->ath_device->ctrl_response_length);
[59fa7ab]92
[8a64320e]93 int rc = wmi_send_command(htc_device, WMI_REG_WRITE,
94 (uint8_t *) &cmd_buffer, sizeof(cmd_buffer), resp_buffer);
[59fa7ab]95
96 free(resp_buffer);
97
[8a64320e]98 if (rc != EOK) {
[59fa7ab]99 usb_log_error("Failed to write registry value.\n");
100 return rc;
101 }
102
103 return rc;
104}
105
[8a64320e]106/** WMI registry set or clear specified bits.
107 *
[59fa7ab]108 * @param htc_device HTC device structure.
109 * @param reg_offset Registry offset (address) to be written.
[8a64320e]110 * @param set_bit Bit to be set.
111 * @param clear_bit Bit to be cleared.
112 *
[59fa7ab]113 * @return EOK if succeed, negative error code otherwise.
[8a64320e]114 *
[59fa7ab]115 */
[8a64320e]116int wmi_reg_set_clear_bit(htc_device_t *htc_device, uint32_t reg_offset,
117 uint32_t set_bit, uint32_t clear_bit)
[59fa7ab]118{
119 uint32_t value;
120
121 int rc = wmi_reg_read(htc_device, reg_offset, &value);
[8a64320e]122 if (rc != EOK) {
[59fa7ab]123 usb_log_error("Failed to read registry value in RMW "
[8a64320e]124 "function.\n");
[59fa7ab]125 return rc;
126 }
127
128 value &= ~clear_bit;
129 value |= set_bit;
130
131 rc = wmi_reg_write(htc_device, reg_offset, value);
[8a64320e]132 if (rc != EOK) {
[59fa7ab]133 usb_log_error("Failed to write registry value in RMW "
[8a64320e]134 "function.\n");
[59fa7ab]135 return rc;
136 }
137
138 return rc;
139}
140
[8a64320e]141/** WMI registry set specified bit.
142 *
[59fa7ab]143 * @param htc_device HTC device structure.
144 * @param reg_offset Registry offset (address) to be written.
[8a64320e]145 * @param set_bit Bit to be set.
146 *
[59fa7ab]147 * @return EOK if succeed, negative error code otherwise.
[8a64320e]148 *
[59fa7ab]149 */
[8a64320e]150int wmi_reg_set_bit(htc_device_t *htc_device, uint32_t reg_offset,
151 uint32_t set_bit)
[59fa7ab]152{
153 return wmi_reg_set_clear_bit(htc_device, reg_offset, set_bit, 0);
154}
155
[8a64320e]156/** WMI registry clear specified bit.
157 *
[59fa7ab]158 * @param htc_device HTC device structure.
159 * @param reg_offset Registry offset (address) to be written.
[8a64320e]160 * @param clear_bit Bit to be cleared.
161 *
[59fa7ab]162 * @return EOK if succeed, negative error code otherwise.
[8a64320e]163 *
[59fa7ab]164 */
[8a64320e]165int wmi_reg_clear_bit(htc_device_t *htc_device, uint32_t reg_offset,
166 uint32_t clear_bit)
[59fa7ab]167{
168 return wmi_reg_set_clear_bit(htc_device, reg_offset, 0, clear_bit);
169}
170
[8a64320e]171/** WMI multi registry write.
172 *
[59fa7ab]173 * @param htc_device HTC device structure.
174 * @param reg_buffer Array of registry values to be written.
[8a64320e]175 * @param elements Number of elements in array.
176 *
[59fa7ab]177 * @return EOK if succeed, negative error code otherwise.
[8a64320e]178 *
[59fa7ab]179 */
180int wmi_reg_buffer_write(htc_device_t *htc_device, wmi_reg_t *reg_buffer,
[8a64320e]181 size_t elements)
[59fa7ab]182{
183 size_t buffer_size = sizeof(wmi_reg_t) * elements;
184 void *buffer = malloc(buffer_size);
[8a64320e]185 void *resp_buffer =
186 malloc(htc_device->ath_device->ctrl_response_length);
[59fa7ab]187
188 /* Convert values to correct endianness. */
[8a64320e]189 for (size_t i = 0; i < elements; i++) {
[59fa7ab]190 wmi_reg_t *buffer_element = &reg_buffer[i];
191 wmi_reg_t *buffer_it = (wmi_reg_t *)
[8a64320e]192 ((void *) buffer + i * sizeof(wmi_reg_t));
193 buffer_it->offset =
194 host2uint32_t_be(buffer_element->offset);
[59fa7ab]195 buffer_it->value =
[8a64320e]196 host2uint32_t_be(buffer_element->value);
[59fa7ab]197 }
198
[8a64320e]199 int rc = wmi_send_command(htc_device, WMI_REG_WRITE,
200 (uint8_t *) buffer, buffer_size, resp_buffer);
[59fa7ab]201
202 free(buffer);
203 free(resp_buffer);
204
[8a64320e]205 if (rc != EOK) {
[59fa7ab]206 usb_log_error("Failed to write multi registry value.\n");
207 return rc;
208 }
209
210 return rc;
211}
212
[8a64320e]213/** Send WMI message to HTC device.
214 *
215 * @param htc_device HTC device structure.
216 * @param command_id Command identification.
217 * @param command_buffer Buffer with command data.
218 * @param command_length Length of command data.
[59fa7ab]219 * @param response_buffer Buffer with response data.
[8a64320e]220 *
[59fa7ab]221 * @return EOK if succeed, negative error code otherwise.
[8a64320e]222 *
[59fa7ab]223 */
[8a64320e]224int wmi_send_command(htc_device_t *htc_device, wmi_command_t command_id,
225 uint8_t *command_buffer, uint32_t command_length, void *response_buffer)
[59fa7ab]226{
[8a64320e]227 size_t header_size = sizeof(wmi_command_header_t) +
228 sizeof(htc_frame_header_t);
[59fa7ab]229 size_t buffer_size = header_size + command_length;
230 void *buffer = malloc(buffer_size);
[1dcc0b9]231
[8a64320e]232 if (command_buffer != NULL)
[1dcc0b9]233 memcpy(buffer+header_size, command_buffer, command_length);
[59fa7ab]234
235 /* Set up WMI header */
236 wmi_command_header_t *wmi_header = (wmi_command_header_t *)
[8a64320e]237 ((void *) buffer + sizeof(htc_frame_header_t));
238 wmi_header->command_id = host2uint16_t_be(command_id);
239 wmi_header->sequence_number =
240 host2uint16_t_be(++htc_device->sequence_number);
[59fa7ab]241
242 /* Send message. */
243 int rc = htc_send_control_message(htc_device, buffer, buffer_size,
[8a64320e]244 htc_device->endpoints.wmi_endpoint);
245 if (rc != EOK) {
[59fa7ab]246 free(buffer);
247 usb_log_error("Failed to send WMI message. Error: %d\n", rc);
248 return rc;
249 }
250
251 free(buffer);
252
253 bool clean_resp_buffer = false;
[8a64320e]254 size_t response_buffer_size =
255 htc_device->ath_device->ctrl_response_length;
256 if (response_buffer == NULL) {
[59fa7ab]257 response_buffer = malloc(response_buffer_size);
258 clean_resp_buffer = true;
259 }
260
261 /* Read response. */
[1dcc0b9]262 /* TODO: Ignoring WMI management RX messages ~ TX statuses etc. */
263 uint16_t cmd_id;
264 do {
[8a64320e]265 rc = htc_read_control_message(htc_device, response_buffer,
266 response_buffer_size, NULL);
267 if (rc != EOK) {
[1dcc0b9]268 free(buffer);
269 usb_log_error("Failed to receive WMI message response. "
270 "Error: %d\n", rc);
271 return rc;
272 }
273
[8a64320e]274 if (response_buffer_size < sizeof(htc_frame_header_t) +
275 sizeof(wmi_command_header_t)) {
[1dcc0b9]276 free(buffer);
277 usb_log_error("Corrupted response received.\n");
278 return EINVAL;
279 }
280
[8a64320e]281 wmi_command_header_t *wmi_hdr = (wmi_command_header_t *)
282 ((void *) response_buffer + sizeof(htc_frame_header_t));
[1dcc0b9]283 cmd_id = uint16_t_be2host(wmi_hdr->command_id);
284 } while(cmd_id & WMI_MGMT_CMD_MASK);
[59fa7ab]285
[8a64320e]286 if (clean_resp_buffer)
[59fa7ab]287 free(response_buffer);
288
289 return rc;
[8a64320e]290}
Note: See TracBrowser for help on using the repository browser.