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 
10 int 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 
48 int 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;
86 end:
87 	kfree(buf);
88 	return err;
89 }
90 
91 static inline void
92 avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr)
93 {
94 	buf[1] = addr[0];
95 	memcpy(buf + 4, addr + 1, 5);
96 }
97 
98 static inline void
99 avc_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 
109 int 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;
141 end:
142 	kfree(buf);
143 	return err;
144 }
145 
146 int 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;
177 end:
178 	kfree(buf);
179 	return err;
180 }
181 
182 int 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;
210 end:
211 	return err;
212 }
213 
214 int 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;
248 end:
249 	kfree(buf);
250 	return err;
251 }
252 
253 int 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;
284 end:
285 	kfree(buf);
286 	return err;
287 }
288 
289 int 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;
329 end:
330 	return err;
331 }
332