1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * bebob_command.c - driver for BeBoB based devices
4 *
5 * Copyright (c) 2013-2014 Takashi Sakamoto
6 */
7
8#include "./bebob.h"
9
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));
33	if (err < 0)
34		;
35	else if (err < 9)
36		err = -EIO;
37	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
38		err = -ENOSYS;
39	else if (buf[0] == 0x0a) /* REJECTED */
40		err = -EINVAL;
41	else
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));
71	if (err < 0)
72		;
73	else if (err < 9)
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
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));
126	if (err < 0)
127		;
128	else if (err < 11)
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_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES],
147				   unsigned int *ch_count)
148{
149	u8 *buf;
150	int err;
151
152	buf = kzalloc(12, GFP_KERNEL);
153	if (buf == NULL)
154		return -ENOMEM;
155
156	// Info type is 'plug type'.
157	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x02);
158
159	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
160				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
161				  BIT(6) | BIT(7) | BIT(9));
162	if (err < 0)
163		;
164	else if (err < 11)
165		err = -EIO;
166	else if (buf[0] == 0x08) // NOT IMPLEMENTED
167		err = -ENOSYS;
168	else if (buf[0] == 0x0a) // REJECTED
169		err = -EINVAL;
170	else if (buf[0] == 0x0b) // IN TRANSITION
171		err = -EAGAIN;
172	if (err < 0)
173		goto end;
174
175	*ch_count = buf[10];
176	err = 0;
177end:
178	kfree(buf);
179	return err;
180}
181
182int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
183				 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
184				 u8 *buf, unsigned int len)
185{
186	int err;
187
188	/* Info type is 'channel position'. */
189	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03);
190
191	err = fcp_avc_transaction(unit, buf, 12, buf, 256,
192				  BIT(1) | BIT(2) | BIT(3) | BIT(4) |
193				  BIT(5) | BIT(6) | BIT(7) | BIT(9));
194	if (err < 0)
195		;
196	else if (err < 11)
197		err = -EIO;
198	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
199		err = -ENOSYS;
200	else if (buf[0] == 0x0a) /* REJECTED */
201		err = -EINVAL;
202	else if (buf[0] == 0x0b) /* IN TRANSITION */
203		err = -EAGAIN;
204	if (err < 0)
205		goto end;
206
207	/* Pick up specific data. */
208	memmove(buf, buf + 10, err - 10);
209	err = 0;
210end:
211	return err;
212}
213
214int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
215				       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
216				       unsigned int id, u8 *type)
217{
218	u8 *buf;
219	int err;
220
221	/* section info includes charactors but this module don't need it */
222	buf = kzalloc(12, GFP_KERNEL);
223	if (buf == NULL)
224		return -ENOMEM;
225
226	/* Info type is 'section info'. */
227	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07);
228	buf[10] = 0xff & ++id;	/* section id */
229
230	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
231				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
232				  BIT(6) | BIT(7) | BIT(9) | BIT(10));
233	if (err < 0)
234		;
235	else if (err < 12)
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	*type = buf[11];
247	err = 0;
248end:
249	kfree(buf);
250	return err;
251}
252
253int avc_bridgeco_get_plug_input(struct fw_unit *unit,
254				u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7])
255{
256	int err;
257	u8 *buf;
258
259	buf = kzalloc(18, GFP_KERNEL);
260	if (buf == NULL)
261		return -ENOMEM;
262
263	/* Info type is 'plug input'. */
264	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05);
265
266	err = fcp_avc_transaction(unit, buf, 16, buf, 16,
267				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
268				  BIT(6) | BIT(7));
269	if (err < 0)
270		;
271	else if (err < 16)
272		err = -EIO;
273	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
274		err = -ENOSYS;
275	else if (buf[0] == 0x0a) /* REJECTED */
276		err = -EINVAL;
277	else if (buf[0] == 0x0b) /* IN TRANSITION */
278		err = -EAGAIN;
279	if (err < 0)
280		goto end;
281
282	memcpy(input, buf + 10, 5);
283	err = 0;
284end:
285	kfree(buf);
286	return err;
287}
288
289int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
290				   u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf,
291				   unsigned int *len, unsigned int eid)
292{
293	int err;
294
295	/* check given buffer */
296	if ((buf == NULL) || (*len < 12)) {
297		err = -EINVAL;
298		goto end;
299	}
300
301	buf[0] = 0x01;	/* AV/C STATUS */
302	buf[2] = 0x2f;	/* AV/C STREAM FORMAT SUPPORT */
303	buf[3] = 0xc1;	/* Bridgeco extension - List Request */
304	avc_bridgeco_fill_extension_addr(buf, addr);
305	buf[10] = 0xff & eid;	/* Entry ID */
306
307	err = fcp_avc_transaction(unit, buf, 12, buf, *len,
308				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
309				  BIT(6) | BIT(7) | BIT(10));
310	if (err < 0)
311		;
312	else if (err < 12)
313		err = -EIO;
314	else if (buf[0] == 0x08)        /* NOT IMPLEMENTED */
315		err = -ENOSYS;
316	else if (buf[0] == 0x0a)        /* REJECTED */
317		err = -EINVAL;
318	else if (buf[0] == 0x0b)        /* IN TRANSITION */
319		err = -EAGAIN;
320	else if (buf[10] != eid)
321		err = -EIO;
322	if (err < 0)
323		goto end;
324
325	/* Pick up 'stream format info'. */
326	memmove(buf, buf + 11, err - 11);
327	*len = err - 11;
328	err = 0;
329end:
330	return err;
331}
332