Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-block.git] / sound / firewire / bebob / bebob_command.c
CommitLineData
da607e19 1// SPDX-License-Identifier: GPL-2.0-only
eb7b3a05
TS
2/*
3 * bebob_command.c - driver for BeBoB based devices
4 *
5 * Copyright (c) 2013-2014 Takashi Sakamoto
eb7b3a05
TS
6 */
7
8#include "./bebob.h"
9
1fc9522a
TS
10int avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id,
11 unsigned int fb_id, unsigned int num)
12{
13 u8 *buf;
14 int err;
15
16 buf = kzalloc(12, GFP_KERNEL);
17 if (buf == NULL)
18 return -ENOMEM;
19
20 buf[0] = 0x00; /* AV/C CONTROL */
21 buf[1] = 0x08 | (0x07 & subunit_id); /* AUDIO SUBUNIT ID */
22 buf[2] = 0xb8; /* FUNCTION BLOCK */
23 buf[3] = 0x80; /* type is 'selector'*/
24 buf[4] = 0xff & fb_id; /* function block id */
25 buf[5] = 0x10; /* control attribute is CURRENT */
26 buf[6] = 0x02; /* selector length is 2 */
27 buf[7] = 0xff & num; /* input function block plug number */
28 buf[8] = 0x01; /* control selector is SELECTOR_CONTROL */
29
30 err = fcp_avc_transaction(unit, buf, 12, buf, 12,
31 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
32 BIT(6) | BIT(7) | BIT(8));
7e1621de
TS
33 if (err < 0)
34 ;
35 else if (err < 9)
1fc9522a
TS
36 err = -EIO;
37 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
38 err = -ENOSYS;
39 else if (buf[0] == 0x0a) /* REJECTED */
40 err = -EINVAL;
7e1621de 41 else
1fc9522a
TS
42 err = 0;
43
44 kfree(buf);
45 return err;
46}
47
48int avc_audio_get_selector(struct fw_unit *unit, unsigned int subunit_id,
49 unsigned int fb_id, unsigned int *num)
50{
51 u8 *buf;
52 int err;
53
54 buf = kzalloc(12, GFP_KERNEL);
55 if (buf == NULL)
56 return -ENOMEM;
57
58 buf[0] = 0x01; /* AV/C STATUS */
59 buf[1] = 0x08 | (0x07 & subunit_id); /* AUDIO SUBUNIT ID */
60 buf[2] = 0xb8; /* FUNCTION BLOCK */
61 buf[3] = 0x80; /* type is 'selector'*/
62 buf[4] = 0xff & fb_id; /* function block id */
63 buf[5] = 0x10; /* control attribute is CURRENT */
64 buf[6] = 0x02; /* selector length is 2 */
65 buf[7] = 0xff; /* input function block plug number */
66 buf[8] = 0x01; /* control selector is SELECTOR_CONTROL */
67
68 err = fcp_avc_transaction(unit, buf, 12, buf, 12,
69 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
70 BIT(6) | BIT(8));
7e1621de
TS
71 if (err < 0)
72 ;
73 else if (err < 9)
1fc9522a
TS
74 err = -EIO;
75 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
76 err = -ENOSYS;
77 else if (buf[0] == 0x0a) /* REJECTED */
78 err = -EINVAL;
79 else if (buf[0] == 0x0b) /* IN TRANSITION */
80 err = -EAGAIN;
81 if (err < 0)
82 goto end;
83
84 *num = buf[7];
85 err = 0;
86end:
87 kfree(buf);
88 return err;
89}
90
eb7b3a05
TS
91static inline void
92avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr)
93{
94 buf[1] = addr[0];
95 memcpy(buf + 4, addr + 1, 5);
96}
97
98static inline void
99avc_bridgeco_fill_plug_info_extension_command(u8 *buf, u8 *addr,
100 unsigned int itype)
101{
102 buf[0] = 0x01; /* AV/C STATUS */
103 buf[2] = 0x02; /* AV/C GENERAL PLUG INFO */
104 buf[3] = 0xc0; /* BridgeCo extension */
105 avc_bridgeco_fill_extension_addr(buf, addr);
106 buf[9] = itype; /* info type */
107}
108
109int avc_bridgeco_get_plug_type(struct fw_unit *unit,
110 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
111 enum avc_bridgeco_plug_type *type)
112{
113 u8 *buf;
114 int err;
115
116 buf = kzalloc(12, GFP_KERNEL);
117 if (buf == NULL)
118 return -ENOMEM;
119
120 /* Info type is 'plug type'. */
121 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x00);
122
123 err = fcp_avc_transaction(unit, buf, 12, buf, 12,
124 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
125 BIT(6) | BIT(7) | BIT(9));
7e1621de
TS
126 if (err < 0)
127 ;
128 else if (err < 11)
eb7b3a05
TS
129 err = -EIO;
130 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
131 err = -ENOSYS;
132 else if (buf[0] == 0x0a) /* REJECTED */
133 err = -EINVAL;
134 else if (buf[0] == 0x0b) /* IN TRANSITION */
135 err = -EAGAIN;
136 if (err < 0)
137 goto end;
138
139 *type = buf[10];
140 err = 0;
141end:
142 kfree(buf);
143 return err;
144}
145
146int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
147 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
148 u8 *buf, unsigned int len)
149{
150 int err;
151
152 /* Info type is 'channel position'. */
153 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03);
154
155 err = fcp_avc_transaction(unit, buf, 12, buf, 256,
156 BIT(1) | BIT(2) | BIT(3) | BIT(4) |
157 BIT(5) | BIT(6) | BIT(7) | BIT(9));
7e1621de
TS
158 if (err < 0)
159 ;
160 else if (err < 11)
eb7b3a05
TS
161 err = -EIO;
162 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
163 err = -ENOSYS;
164 else if (buf[0] == 0x0a) /* REJECTED */
165 err = -EINVAL;
166 else if (buf[0] == 0x0b) /* IN TRANSITION */
167 err = -EAGAIN;
168 if (err < 0)
169 goto end;
170
171 /* Pick up specific data. */
172 memmove(buf, buf + 10, err - 10);
173 err = 0;
174end:
175 return err;
176}
177
178int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
179 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
180 unsigned int id, u8 *type)
181{
182 u8 *buf;
183 int err;
184
185 /* section info includes charactors but this module don't need it */
186 buf = kzalloc(12, GFP_KERNEL);
187 if (buf == NULL)
188 return -ENOMEM;
189
190 /* Info type is 'section info'. */
191 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07);
192 buf[10] = 0xff & ++id; /* section id */
193
194 err = fcp_avc_transaction(unit, buf, 12, buf, 12,
195 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
196 BIT(6) | BIT(7) | BIT(9) | BIT(10));
7e1621de
TS
197 if (err < 0)
198 ;
199 else if (err < 12)
eb7b3a05
TS
200 err = -EIO;
201 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
202 err = -ENOSYS;
203 else if (buf[0] == 0x0a) /* REJECTED */
204 err = -EINVAL;
205 else if (buf[0] == 0x0b) /* IN TRANSITION */
206 err = -EAGAIN;
207 if (err < 0)
208 goto end;
209
210 *type = buf[11];
211 err = 0;
212end:
213 kfree(buf);
214 return err;
215}
216
217int avc_bridgeco_get_plug_input(struct fw_unit *unit,
218 u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7])
219{
220 int err;
221 u8 *buf;
222
223 buf = kzalloc(18, GFP_KERNEL);
224 if (buf == NULL)
225 return -ENOMEM;
226
227 /* Info type is 'plug input'. */
228 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05);
229
230 err = fcp_avc_transaction(unit, buf, 16, buf, 16,
231 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
232 BIT(6) | BIT(7));
7e1621de
TS
233 if (err < 0)
234 ;
235 else if (err < 16)
eb7b3a05
TS
236 err = -EIO;
237 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
238 err = -ENOSYS;
239 else if (buf[0] == 0x0a) /* REJECTED */
240 err = -EINVAL;
241 else if (buf[0] == 0x0b) /* IN TRANSITION */
242 err = -EAGAIN;
243 if (err < 0)
244 goto end;
245
246 memcpy(input, buf + 10, 5);
247 err = 0;
248end:
249 kfree(buf);
250 return err;
251}
252
253int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
254 u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf,
255 unsigned int *len, unsigned int eid)
256{
257 int err;
258
259 /* check given buffer */
260 if ((buf == NULL) || (*len < 12)) {
261 err = -EINVAL;
262 goto end;
263 }
264
265 buf[0] = 0x01; /* AV/C STATUS */
266 buf[2] = 0x2f; /* AV/C STREAM FORMAT SUPPORT */
267 buf[3] = 0xc1; /* Bridgeco extension - List Request */
268 avc_bridgeco_fill_extension_addr(buf, addr);
269 buf[10] = 0xff & eid; /* Entry ID */
270
271 err = fcp_avc_transaction(unit, buf, 12, buf, *len,
272 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
273 BIT(6) | BIT(7) | BIT(10));
7e1621de
TS
274 if (err < 0)
275 ;
276 else if (err < 12)
eb7b3a05
TS
277 err = -EIO;
278 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
279 err = -ENOSYS;
280 else if (buf[0] == 0x0a) /* REJECTED */
281 err = -EINVAL;
282 else if (buf[0] == 0x0b) /* IN TRANSITION */
283 err = -EAGAIN;
284 else if (buf[10] != eid)
285 err = -EIO;
286 if (err < 0)
287 goto end;
288
289 /* Pick up 'stream format info'. */
290 memmove(buf, buf + 11, err - 11);
291 *len = err - 11;
292 err = 0;
293end:
294 return err;
295}