blob: 08bfdeb87a61264846c44c4fe885e74d17a1740a [file] [log] [blame]
Mark Greer184992e2016-01-13 14:07:46 -07001/*
2 * Greybus Audio Device Class Protocol helpers
3 *
4 * Copyright 2015-2016 Google Inc.
5 *
6 * Released under the GPLv2 only.
7 */
8
9#include "greybus.h"
10#include "greybus_protocols.h"
11#include "operation.h"
12
13/* TODO: Split into separate calls */
14int gb_audio_gb_get_topology(struct gb_connection *connection,
15 struct gb_audio_topology **topology)
16{
17 struct gb_audio_get_topology_size_response size_resp;
18 struct gb_audio_topology *topo;
19 uint16_t size;
20 int ret;
21
22 ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TOPOLOGY_SIZE,
23 NULL, 0, &size_resp, sizeof(size_resp));
24 if (ret)
25 return ret;
26
27 size = le16_to_cpu(size_resp.size);
28 if (size < sizeof(*topo))
29 return -ENODATA;
30
31 topo = kzalloc(size, GFP_KERNEL);
32 if (!topo)
33 return -ENOMEM;
34
35 ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TOPOLOGY, NULL, 0,
36 topo, size);
37 if (ret) {
38 kfree(topo);
39 return ret;
40 }
41
42 *topology = topo;
43
44 return 0;
45}
46EXPORT_SYMBOL_GPL(gb_audio_gb_get_topology);
47
48int gb_audio_gb_get_control(struct gb_connection *connection,
49 uint8_t control_id, uint8_t index,
50 struct gb_audio_ctl_elem_value *value)
51{
52 struct gb_audio_get_control_request req;
53 struct gb_audio_get_control_response resp;
54 int ret;
55
56 req.control_id = control_id;
57 req.index = index;
58
59 ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_CONTROL,
60 &req, sizeof(req), &resp, sizeof(resp));
61 if (ret)
62 return ret;
63
64 memcpy(value, &resp.value, sizeof(*value));
65
66 return 0;
67}
68EXPORT_SYMBOL_GPL(gb_audio_gb_get_control);
69
70int gb_audio_gb_set_control(struct gb_connection *connection,
71 uint8_t control_id, uint8_t index,
72 struct gb_audio_ctl_elem_value *value)
73{
74 struct gb_audio_set_control_request req;
75
76 req.control_id = control_id;
77 req.index = index;
78 memcpy(&req.value, value, sizeof(req.value));
79
80 return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_CONTROL,
81 &req, sizeof(req), NULL, 0);
82}
83EXPORT_SYMBOL_GPL(gb_audio_gb_set_control);
84
85int gb_audio_gb_enable_widget(struct gb_connection *connection,
86 uint8_t widget_id)
87{
88 struct gb_audio_enable_widget_request req;
89
90 req.widget_id = widget_id;
91
92 return gb_operation_sync(connection, GB_AUDIO_TYPE_ENABLE_WIDGET,
93 &req, sizeof(req), NULL, 0);
94}
95EXPORT_SYMBOL_GPL(gb_audio_gb_enable_widget);
96
97int gb_audio_gb_disable_widget(struct gb_connection *connection,
98 uint8_t widget_id)
99{
100 struct gb_audio_disable_widget_request req;
101
102 req.widget_id = widget_id;
103
104 return gb_operation_sync(connection, GB_AUDIO_TYPE_DISABLE_WIDGET,
105 &req, sizeof(req), NULL, 0);
106}
107EXPORT_SYMBOL_GPL(gb_audio_gb_disable_widget);
108
109int gb_audio_gb_get_pcm(struct gb_connection *connection, uint16_t data_cport,
110 uint32_t *format, uint32_t *rate, uint8_t *channels,
111 uint8_t *sig_bits)
112{
113 struct gb_audio_get_pcm_request req;
114 struct gb_audio_get_pcm_response resp;
115 int ret;
116
117 req.data_cport = cpu_to_le16(data_cport);
118
119 ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_PCM,
120 &req, sizeof(req), &resp, sizeof(resp));
121 if (ret)
122 return ret;
123
124 *format = le32_to_cpu(resp.format);
125 *rate = le32_to_cpu(resp.rate);
126 *channels = resp.channels;
127 *sig_bits = resp.sig_bits;
128
129 return 0;
130}
131EXPORT_SYMBOL_GPL(gb_audio_gb_get_pcm);
132
133int gb_audio_gb_set_pcm(struct gb_connection *connection, uint16_t data_cport,
134 uint32_t format, uint32_t rate, uint8_t channels,
135 uint8_t sig_bits)
136{
137 struct gb_audio_set_pcm_request req;
138
139 req.data_cport = cpu_to_le16(data_cport);
140 req.format = cpu_to_le32(format);
141 req.rate = cpu_to_le32(rate);
142 req.channels = channels;
143 req.sig_bits = sig_bits;
144
145 return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_PCM,
146 &req, sizeof(req), NULL, 0);
147}
148EXPORT_SYMBOL_GPL(gb_audio_gb_set_pcm);
149
150int gb_audio_gb_set_tx_data_size(struct gb_connection *connection,
151 uint16_t data_cport, uint16_t size)
152{
153 struct gb_audio_set_tx_data_size_request req;
154
155 req.data_cport = cpu_to_le16(data_cport);
156 req.size = cpu_to_le16(size);
157
158 return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_TX_DATA_SIZE,
159 &req, sizeof(req), NULL, 0);
160}
161EXPORT_SYMBOL_GPL(gb_audio_gb_set_tx_data_size);
162
163int gb_audio_gb_get_tx_delay(struct gb_connection *connection,
164 uint16_t data_cport, uint32_t *delay)
165{
166 struct gb_audio_get_tx_delay_request req;
167 struct gb_audio_get_tx_delay_response resp;
168 int ret;
169
170 req.data_cport = cpu_to_le16(data_cport);
171
172 ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TX_DELAY,
173 &req, sizeof(req), &resp, sizeof(resp));
174 if (ret)
175 return ret;
176
177 *delay = le32_to_cpu(resp.delay);
178
179 return 0;
180}
181EXPORT_SYMBOL_GPL(gb_audio_gb_get_tx_delay);
182
183int gb_audio_gb_activate_tx(struct gb_connection *connection,
184 uint16_t data_cport)
185{
186 struct gb_audio_activate_tx_request req;
187
188 req.data_cport = cpu_to_le16(data_cport);
189
190 return gb_operation_sync(connection, GB_AUDIO_TYPE_ACTIVATE_TX,
191 &req, sizeof(req), NULL, 0);
192}
193EXPORT_SYMBOL_GPL(gb_audio_gb_activate_tx);
194
195int gb_audio_gb_deactivate_tx(struct gb_connection *connection,
196 uint16_t data_cport)
197{
198 struct gb_audio_deactivate_tx_request req;
199
200 req.data_cport = cpu_to_le16(data_cport);
201
202 return gb_operation_sync(connection, GB_AUDIO_TYPE_DEACTIVATE_TX,
203 &req, sizeof(req), NULL, 0);
204}
205EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_tx);
206
207int gb_audio_gb_set_rx_data_size(struct gb_connection *connection,
208 uint16_t data_cport, uint16_t size)
209{
210 struct gb_audio_set_rx_data_size_request req;
211
212 req.data_cport = cpu_to_le16(data_cport);
213 req.size = cpu_to_le16(size);
214
215 return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_RX_DATA_SIZE,
216 &req, sizeof(req), NULL, 0);
217}
218EXPORT_SYMBOL_GPL(gb_audio_gb_set_rx_data_size);
219
220int gb_audio_gb_get_rx_delay(struct gb_connection *connection,
221 uint16_t data_cport, uint32_t *delay)
222{
223 struct gb_audio_get_rx_delay_request req;
224 struct gb_audio_get_rx_delay_response resp;
225 int ret;
226
227 req.data_cport = cpu_to_le16(data_cport);
228
229 ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_RX_DELAY,
230 &req, sizeof(req), &resp, sizeof(resp));
231 if (ret)
232 return ret;
233
234 *delay = le32_to_cpu(resp.delay);
235
236 return 0;
237}
238EXPORT_SYMBOL_GPL(gb_audio_gb_get_rx_delay);
239
240int gb_audio_gb_activate_rx(struct gb_connection *connection,
241 uint16_t data_cport)
242{
243 struct gb_audio_activate_rx_request req;
244
245 req.data_cport = cpu_to_le16(data_cport);
246
247 return gb_operation_sync(connection, GB_AUDIO_TYPE_ACTIVATE_RX,
248 &req, sizeof(req), NULL, 0);
249}
250EXPORT_SYMBOL_GPL(gb_audio_gb_activate_rx);
251
252int gb_audio_gb_deactivate_rx(struct gb_connection *connection,
253 uint16_t data_cport)
254{
255 struct gb_audio_deactivate_rx_request req;
256
257 req.data_cport = cpu_to_le16(data_cport);
258
259 return gb_operation_sync(connection, GB_AUDIO_TYPE_DEACTIVATE_RX,
260 &req, sizeof(req), NULL, 0);
261}
262EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_rx);
263
264MODULE_LICENSE("GPL v2");
265MODULE_ALIAS("greybus:audio-gb");
266MODULE_DESCRIPTION("Greybus Audio Device Class Protocol library");
267MODULE_AUTHOR("Mark Greer <mgreer@animalcreek.com>");