1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2eb7b3a05STakashi Sakamoto /*
3eb7b3a05STakashi Sakamoto  * bebob_command.c - driver for BeBoB based devices
4eb7b3a05STakashi Sakamoto  *
5eb7b3a05STakashi Sakamoto  * Copyright (c) 2013-2014 Takashi Sakamoto
6eb7b3a05STakashi Sakamoto  */
7eb7b3a05STakashi Sakamoto 
8eb7b3a05STakashi Sakamoto #include "./bebob.h"
9eb7b3a05STakashi Sakamoto 
101fc9522aSTakashi Sakamoto int avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id,
111fc9522aSTakashi Sakamoto 			   unsigned int fb_id, unsigned int num)
121fc9522aSTakashi Sakamoto {
131fc9522aSTakashi Sakamoto 	u8 *buf;
141fc9522aSTakashi Sakamoto 	int err;
151fc9522aSTakashi Sakamoto 
161fc9522aSTakashi Sakamoto 	buf = kzalloc(12, GFP_KERNEL);
171fc9522aSTakashi Sakamoto 	if (buf == NULL)
181fc9522aSTakashi Sakamoto 		return -ENOMEM;
191fc9522aSTakashi Sakamoto 
201fc9522aSTakashi Sakamoto 	buf[0]  = 0x00;		/* AV/C CONTROL */
211fc9522aSTakashi Sakamoto 	buf[1]  = 0x08 | (0x07 & subunit_id);	/* AUDIO SUBUNIT ID */
221fc9522aSTakashi Sakamoto 	buf[2]  = 0xb8;		/* FUNCTION BLOCK  */
231fc9522aSTakashi Sakamoto 	buf[3]  = 0x80;		/* type is 'selector'*/
241fc9522aSTakashi Sakamoto 	buf[4]  = 0xff & fb_id;	/* function block id */
251fc9522aSTakashi Sakamoto 	buf[5]  = 0x10;		/* control attribute is CURRENT */
261fc9522aSTakashi Sakamoto 	buf[6]  = 0x02;		/* selector length is 2 */
271fc9522aSTakashi Sakamoto 	buf[7]  = 0xff & num;	/* input function block plug number */
281fc9522aSTakashi Sakamoto 	buf[8]  = 0x01;		/* control selector is SELECTOR_CONTROL */
291fc9522aSTakashi Sakamoto 
301fc9522aSTakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
311fc9522aSTakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
321fc9522aSTakashi Sakamoto 				  BIT(6) | BIT(7) | BIT(8));
337e1621deSTakashi Sakamoto 	if (err < 0)
347e1621deSTakashi Sakamoto 		;
357e1621deSTakashi Sakamoto 	else if (err < 9)
361fc9522aSTakashi Sakamoto 		err = -EIO;
371fc9522aSTakashi Sakamoto 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
381fc9522aSTakashi Sakamoto 		err = -ENOSYS;
391fc9522aSTakashi Sakamoto 	else if (buf[0] == 0x0a) /* REJECTED */
401fc9522aSTakashi Sakamoto 		err = -EINVAL;
417e1621deSTakashi Sakamoto 	else
421fc9522aSTakashi Sakamoto 		err = 0;
431fc9522aSTakashi Sakamoto 
441fc9522aSTakashi Sakamoto 	kfree(buf);
451fc9522aSTakashi Sakamoto 	return err;
461fc9522aSTakashi Sakamoto }
471fc9522aSTakashi Sakamoto 
481fc9522aSTakashi Sakamoto int avc_audio_get_selector(struct fw_unit *unit, unsigned int subunit_id,
491fc9522aSTakashi Sakamoto 			   unsigned int fb_id, unsigned int *num)
501fc9522aSTakashi Sakamoto {
511fc9522aSTakashi Sakamoto 	u8 *buf;
521fc9522aSTakashi Sakamoto 	int err;
531fc9522aSTakashi Sakamoto 
541fc9522aSTakashi Sakamoto 	buf = kzalloc(12, GFP_KERNEL);
551fc9522aSTakashi Sakamoto 	if (buf == NULL)
561fc9522aSTakashi Sakamoto 		return -ENOMEM;
571fc9522aSTakashi Sakamoto 
581fc9522aSTakashi Sakamoto 	buf[0]  = 0x01;		/* AV/C STATUS */
591fc9522aSTakashi Sakamoto 	buf[1]  = 0x08 | (0x07 & subunit_id);	/* AUDIO SUBUNIT ID */
601fc9522aSTakashi Sakamoto 	buf[2]  = 0xb8;		/* FUNCTION BLOCK */
611fc9522aSTakashi Sakamoto 	buf[3]  = 0x80;		/* type is 'selector'*/
621fc9522aSTakashi Sakamoto 	buf[4]  = 0xff & fb_id;	/* function block id */
631fc9522aSTakashi Sakamoto 	buf[5]  = 0x10;		/* control attribute is CURRENT */
641fc9522aSTakashi Sakamoto 	buf[6]  = 0x02;		/* selector length is 2 */
651fc9522aSTakashi Sakamoto 	buf[7]  = 0xff;		/* input function block plug number */
661fc9522aSTakashi Sakamoto 	buf[8]  = 0x01;		/* control selector is SELECTOR_CONTROL */
671fc9522aSTakashi Sakamoto 
681fc9522aSTakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
691fc9522aSTakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
701fc9522aSTakashi Sakamoto 				  BIT(6) | BIT(8));
717e1621deSTakashi Sakamoto 	if (err < 0)
727e1621deSTakashi Sakamoto 		;
737e1621deSTakashi Sakamoto 	else if (err < 9)
741fc9522aSTakashi Sakamoto 		err = -EIO;
751fc9522aSTakashi Sakamoto 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
761fc9522aSTakashi Sakamoto 		err = -ENOSYS;
771fc9522aSTakashi Sakamoto 	else if (buf[0] == 0x0a) /* REJECTED */
781fc9522aSTakashi Sakamoto 		err = -EINVAL;
791fc9522aSTakashi Sakamoto 	else if (buf[0] == 0x0b) /* IN TRANSITION */
801fc9522aSTakashi Sakamoto 		err = -EAGAIN;
811fc9522aSTakashi Sakamoto 	if (err < 0)
821fc9522aSTakashi Sakamoto 		goto end;
831fc9522aSTakashi Sakamoto 
841fc9522aSTakashi Sakamoto 	*num = buf[7];
851fc9522aSTakashi Sakamoto 	err = 0;
861fc9522aSTakashi Sakamoto end:
871fc9522aSTakashi Sakamoto 	kfree(buf);
881fc9522aSTakashi Sakamoto 	return err;
891fc9522aSTakashi Sakamoto }
901fc9522aSTakashi Sakamoto 
91eb7b3a05STakashi Sakamoto static inline void
92eb7b3a05STakashi Sakamoto avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr)
93eb7b3a05STakashi Sakamoto {
94eb7b3a05STakashi Sakamoto 	buf[1] = addr[0];
95eb7b3a05STakashi Sakamoto 	memcpy(buf + 4, addr + 1, 5);
96eb7b3a05STakashi Sakamoto }
97eb7b3a05STakashi Sakamoto 
98eb7b3a05STakashi Sakamoto static inline void
99eb7b3a05STakashi Sakamoto avc_bridgeco_fill_plug_info_extension_command(u8 *buf, u8 *addr,
100eb7b3a05STakashi Sakamoto 					      unsigned int itype)
101eb7b3a05STakashi Sakamoto {
102eb7b3a05STakashi Sakamoto 	buf[0] = 0x01;	/* AV/C STATUS */
103eb7b3a05STakashi Sakamoto 	buf[2] = 0x02;	/* AV/C GENERAL PLUG INFO */
104eb7b3a05STakashi Sakamoto 	buf[3] = 0xc0;	/* BridgeCo extension */
105eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_extension_addr(buf, addr);
106eb7b3a05STakashi Sakamoto 	buf[9] = itype;	/* info type */
107eb7b3a05STakashi Sakamoto }
108eb7b3a05STakashi Sakamoto 
109eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_type(struct fw_unit *unit,
110eb7b3a05STakashi Sakamoto 			       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
111eb7b3a05STakashi Sakamoto 			       enum avc_bridgeco_plug_type *type)
112eb7b3a05STakashi Sakamoto {
113eb7b3a05STakashi Sakamoto 	u8 *buf;
114eb7b3a05STakashi Sakamoto 	int err;
115eb7b3a05STakashi Sakamoto 
116eb7b3a05STakashi Sakamoto 	buf = kzalloc(12, GFP_KERNEL);
117eb7b3a05STakashi Sakamoto 	if (buf == NULL)
118eb7b3a05STakashi Sakamoto 		return -ENOMEM;
119eb7b3a05STakashi Sakamoto 
120eb7b3a05STakashi Sakamoto 	/* Info type is 'plug type'. */
121eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x00);
122eb7b3a05STakashi Sakamoto 
123eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
124eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
125eb7b3a05STakashi Sakamoto 				  BIT(6) | BIT(7) | BIT(9));
1267e1621deSTakashi Sakamoto 	if (err < 0)
1277e1621deSTakashi Sakamoto 		;
1287e1621deSTakashi Sakamoto 	else if (err < 11)
129eb7b3a05STakashi Sakamoto 		err = -EIO;
130eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
131eb7b3a05STakashi Sakamoto 		err = -ENOSYS;
132eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0a) /* REJECTED */
133eb7b3a05STakashi Sakamoto 		err = -EINVAL;
134eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0b) /* IN TRANSITION */
135eb7b3a05STakashi Sakamoto 		err = -EAGAIN;
136eb7b3a05STakashi Sakamoto 	if (err < 0)
137eb7b3a05STakashi Sakamoto 		goto end;
138eb7b3a05STakashi Sakamoto 
139eb7b3a05STakashi Sakamoto 	*type = buf[10];
140eb7b3a05STakashi Sakamoto 	err = 0;
141eb7b3a05STakashi Sakamoto end:
142eb7b3a05STakashi Sakamoto 	kfree(buf);
143eb7b3a05STakashi Sakamoto 	return err;
144eb7b3a05STakashi Sakamoto }
145eb7b3a05STakashi Sakamoto 
146eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
147eb7b3a05STakashi Sakamoto 				 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
148eb7b3a05STakashi Sakamoto 				 u8 *buf, unsigned int len)
149eb7b3a05STakashi Sakamoto {
150eb7b3a05STakashi Sakamoto 	int err;
151eb7b3a05STakashi Sakamoto 
152eb7b3a05STakashi Sakamoto 	/* Info type is 'channel position'. */
153eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03);
154eb7b3a05STakashi Sakamoto 
155eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, 256,
156eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) |
157eb7b3a05STakashi Sakamoto 				  BIT(5) | BIT(6) | BIT(7) | BIT(9));
1587e1621deSTakashi Sakamoto 	if (err < 0)
1597e1621deSTakashi Sakamoto 		;
1607e1621deSTakashi Sakamoto 	else if (err < 11)
161eb7b3a05STakashi Sakamoto 		err = -EIO;
162eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
163eb7b3a05STakashi Sakamoto 		err = -ENOSYS;
164eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0a) /* REJECTED */
165eb7b3a05STakashi Sakamoto 		err = -EINVAL;
166eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0b) /* IN TRANSITION */
167eb7b3a05STakashi Sakamoto 		err = -EAGAIN;
168eb7b3a05STakashi Sakamoto 	if (err < 0)
169eb7b3a05STakashi Sakamoto 		goto end;
170eb7b3a05STakashi Sakamoto 
171eb7b3a05STakashi Sakamoto 	/* Pick up specific data. */
172eb7b3a05STakashi Sakamoto 	memmove(buf, buf + 10, err - 10);
173eb7b3a05STakashi Sakamoto 	err = 0;
174eb7b3a05STakashi Sakamoto end:
175eb7b3a05STakashi Sakamoto 	return err;
176eb7b3a05STakashi Sakamoto }
177eb7b3a05STakashi Sakamoto 
178eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
179eb7b3a05STakashi Sakamoto 				       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
180eb7b3a05STakashi Sakamoto 				       unsigned int id, u8 *type)
181eb7b3a05STakashi Sakamoto {
182eb7b3a05STakashi Sakamoto 	u8 *buf;
183eb7b3a05STakashi Sakamoto 	int err;
184eb7b3a05STakashi Sakamoto 
185eb7b3a05STakashi Sakamoto 	/* section info includes charactors but this module don't need it */
186eb7b3a05STakashi Sakamoto 	buf = kzalloc(12, GFP_KERNEL);
187eb7b3a05STakashi Sakamoto 	if (buf == NULL)
188eb7b3a05STakashi Sakamoto 		return -ENOMEM;
189eb7b3a05STakashi Sakamoto 
190eb7b3a05STakashi Sakamoto 	/* Info type is 'section info'. */
191eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07);
192eb7b3a05STakashi Sakamoto 	buf[10] = 0xff & ++id;	/* section id */
193eb7b3a05STakashi Sakamoto 
194eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
195eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
196eb7b3a05STakashi Sakamoto 				  BIT(6) | BIT(7) | BIT(9) | BIT(10));
1977e1621deSTakashi Sakamoto 	if (err < 0)
1987e1621deSTakashi Sakamoto 		;
1997e1621deSTakashi Sakamoto 	else if (err < 12)
200eb7b3a05STakashi Sakamoto 		err = -EIO;
201eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
202eb7b3a05STakashi Sakamoto 		err = -ENOSYS;
203eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0a) /* REJECTED */
204eb7b3a05STakashi Sakamoto 		err = -EINVAL;
205eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0b) /* IN TRANSITION */
206eb7b3a05STakashi Sakamoto 		err = -EAGAIN;
207eb7b3a05STakashi Sakamoto 	if (err < 0)
208eb7b3a05STakashi Sakamoto 		goto end;
209eb7b3a05STakashi Sakamoto 
210eb7b3a05STakashi Sakamoto 	*type = buf[11];
211eb7b3a05STakashi Sakamoto 	err = 0;
212eb7b3a05STakashi Sakamoto end:
213eb7b3a05STakashi Sakamoto 	kfree(buf);
214eb7b3a05STakashi Sakamoto 	return err;
215eb7b3a05STakashi Sakamoto }
216eb7b3a05STakashi Sakamoto 
217eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_input(struct fw_unit *unit,
218eb7b3a05STakashi Sakamoto 				u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7])
219eb7b3a05STakashi Sakamoto {
220eb7b3a05STakashi Sakamoto 	int err;
221eb7b3a05STakashi Sakamoto 	u8 *buf;
222eb7b3a05STakashi Sakamoto 
223eb7b3a05STakashi Sakamoto 	buf = kzalloc(18, GFP_KERNEL);
224eb7b3a05STakashi Sakamoto 	if (buf == NULL)
225eb7b3a05STakashi Sakamoto 		return -ENOMEM;
226eb7b3a05STakashi Sakamoto 
227eb7b3a05STakashi Sakamoto 	/* Info type is 'plug input'. */
228eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05);
229eb7b3a05STakashi Sakamoto 
230eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 16, buf, 16,
231eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
232eb7b3a05STakashi Sakamoto 				  BIT(6) | BIT(7));
2337e1621deSTakashi Sakamoto 	if (err < 0)
2347e1621deSTakashi Sakamoto 		;
2357e1621deSTakashi Sakamoto 	else if (err < 16)
236eb7b3a05STakashi Sakamoto 		err = -EIO;
237eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
238eb7b3a05STakashi Sakamoto 		err = -ENOSYS;
239eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0a) /* REJECTED */
240eb7b3a05STakashi Sakamoto 		err = -EINVAL;
241eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0b) /* IN TRANSITION */
242eb7b3a05STakashi Sakamoto 		err = -EAGAIN;
243eb7b3a05STakashi Sakamoto 	if (err < 0)
244eb7b3a05STakashi Sakamoto 		goto end;
245eb7b3a05STakashi Sakamoto 
246eb7b3a05STakashi Sakamoto 	memcpy(input, buf + 10, 5);
247eb7b3a05STakashi Sakamoto 	err = 0;
248eb7b3a05STakashi Sakamoto end:
249eb7b3a05STakashi Sakamoto 	kfree(buf);
250eb7b3a05STakashi Sakamoto 	return err;
251eb7b3a05STakashi Sakamoto }
252eb7b3a05STakashi Sakamoto 
253eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
254eb7b3a05STakashi Sakamoto 				   u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf,
255eb7b3a05STakashi Sakamoto 				   unsigned int *len, unsigned int eid)
256eb7b3a05STakashi Sakamoto {
257eb7b3a05STakashi Sakamoto 	int err;
258eb7b3a05STakashi Sakamoto 
259eb7b3a05STakashi Sakamoto 	/* check given buffer */
260eb7b3a05STakashi Sakamoto 	if ((buf == NULL) || (*len < 12)) {
261eb7b3a05STakashi Sakamoto 		err = -EINVAL;
262eb7b3a05STakashi Sakamoto 		goto end;
263eb7b3a05STakashi Sakamoto 	}
264eb7b3a05STakashi Sakamoto 
265eb7b3a05STakashi Sakamoto 	buf[0] = 0x01;	/* AV/C STATUS */
266eb7b3a05STakashi Sakamoto 	buf[2] = 0x2f;	/* AV/C STREAM FORMAT SUPPORT */
267eb7b3a05STakashi Sakamoto 	buf[3] = 0xc1;	/* Bridgeco extension - List Request */
268eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_extension_addr(buf, addr);
269eb7b3a05STakashi Sakamoto 	buf[10] = 0xff & eid;	/* Entry ID */
270eb7b3a05STakashi Sakamoto 
271eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, *len,
272eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
273eb7b3a05STakashi Sakamoto 				  BIT(6) | BIT(7) | BIT(10));
2747e1621deSTakashi Sakamoto 	if (err < 0)
2757e1621deSTakashi Sakamoto 		;
2767e1621deSTakashi Sakamoto 	else if (err < 12)
277eb7b3a05STakashi Sakamoto 		err = -EIO;
278eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x08)        /* NOT IMPLEMENTED */
279eb7b3a05STakashi Sakamoto 		err = -ENOSYS;
280eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0a)        /* REJECTED */
281eb7b3a05STakashi Sakamoto 		err = -EINVAL;
282eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0b)        /* IN TRANSITION */
283eb7b3a05STakashi Sakamoto 		err = -EAGAIN;
284eb7b3a05STakashi Sakamoto 	else if (buf[10] != eid)
285eb7b3a05STakashi Sakamoto 		err = -EIO;
286eb7b3a05STakashi Sakamoto 	if (err < 0)
287eb7b3a05STakashi Sakamoto 		goto end;
288eb7b3a05STakashi Sakamoto 
289eb7b3a05STakashi Sakamoto 	/* Pick up 'stream format info'. */
290eb7b3a05STakashi Sakamoto 	memmove(buf, buf + 11, err - 11);
291eb7b3a05STakashi Sakamoto 	*len = err - 11;
292eb7b3a05STakashi Sakamoto 	err = 0;
293eb7b3a05STakashi Sakamoto end:
294eb7b3a05STakashi Sakamoto 	return err;
295eb7b3a05STakashi Sakamoto }
296