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 
avc_audio_set_selector(struct fw_unit * unit,unsigned int subunit_id,unsigned int fb_id,unsigned int num)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 
avc_audio_get_selector(struct fw_unit * unit,unsigned int subunit_id,unsigned int fb_id,unsigned int * num)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
avc_bridgeco_fill_extension_addr(u8 * buf,u8 * addr)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
avc_bridgeco_fill_plug_info_extension_command(u8 * buf,u8 * addr,unsigned int itype)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 
avc_bridgeco_get_plug_type(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],enum avc_bridgeco_plug_type * type)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 
avc_bridgeco_get_plug_ch_count(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],unsigned int * ch_count)146*5c6ea94fSTakashi Sakamoto int avc_bridgeco_get_plug_ch_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES],
147*5c6ea94fSTakashi Sakamoto 				   unsigned int *ch_count)
148*5c6ea94fSTakashi Sakamoto {
149*5c6ea94fSTakashi Sakamoto 	u8 *buf;
150*5c6ea94fSTakashi Sakamoto 	int err;
151*5c6ea94fSTakashi Sakamoto 
152*5c6ea94fSTakashi Sakamoto 	buf = kzalloc(12, GFP_KERNEL);
153*5c6ea94fSTakashi Sakamoto 	if (buf == NULL)
154*5c6ea94fSTakashi Sakamoto 		return -ENOMEM;
155*5c6ea94fSTakashi Sakamoto 
156*5c6ea94fSTakashi Sakamoto 	// Info type is 'plug type'.
157*5c6ea94fSTakashi Sakamoto 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x02);
158*5c6ea94fSTakashi Sakamoto 
159*5c6ea94fSTakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
160*5c6ea94fSTakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
161*5c6ea94fSTakashi Sakamoto 				  BIT(6) | BIT(7) | BIT(9));
162*5c6ea94fSTakashi Sakamoto 	if (err < 0)
163*5c6ea94fSTakashi Sakamoto 		;
164*5c6ea94fSTakashi Sakamoto 	else if (err < 11)
165*5c6ea94fSTakashi Sakamoto 		err = -EIO;
166*5c6ea94fSTakashi Sakamoto 	else if (buf[0] == 0x08) // NOT IMPLEMENTED
167*5c6ea94fSTakashi Sakamoto 		err = -ENOSYS;
168*5c6ea94fSTakashi Sakamoto 	else if (buf[0] == 0x0a) // REJECTED
169*5c6ea94fSTakashi Sakamoto 		err = -EINVAL;
170*5c6ea94fSTakashi Sakamoto 	else if (buf[0] == 0x0b) // IN TRANSITION
171*5c6ea94fSTakashi Sakamoto 		err = -EAGAIN;
172*5c6ea94fSTakashi Sakamoto 	if (err < 0)
173*5c6ea94fSTakashi Sakamoto 		goto end;
174*5c6ea94fSTakashi Sakamoto 
175*5c6ea94fSTakashi Sakamoto 	*ch_count = buf[10];
176*5c6ea94fSTakashi Sakamoto 	err = 0;
177*5c6ea94fSTakashi Sakamoto end:
178*5c6ea94fSTakashi Sakamoto 	kfree(buf);
179*5c6ea94fSTakashi Sakamoto 	return err;
180*5c6ea94fSTakashi Sakamoto }
181*5c6ea94fSTakashi Sakamoto 
avc_bridgeco_get_plug_ch_pos(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],u8 * buf,unsigned int len)182eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
183eb7b3a05STakashi Sakamoto 				 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
184eb7b3a05STakashi Sakamoto 				 u8 *buf, unsigned int len)
185eb7b3a05STakashi Sakamoto {
186eb7b3a05STakashi Sakamoto 	int err;
187eb7b3a05STakashi Sakamoto 
188eb7b3a05STakashi Sakamoto 	/* Info type is 'channel position'. */
189eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03);
190eb7b3a05STakashi Sakamoto 
191eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, 256,
192eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) |
193eb7b3a05STakashi Sakamoto 				  BIT(5) | BIT(6) | BIT(7) | BIT(9));
1947e1621deSTakashi Sakamoto 	if (err < 0)
1957e1621deSTakashi Sakamoto 		;
1967e1621deSTakashi Sakamoto 	else if (err < 11)
197eb7b3a05STakashi Sakamoto 		err = -EIO;
198eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
199eb7b3a05STakashi Sakamoto 		err = -ENOSYS;
200eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0a) /* REJECTED */
201eb7b3a05STakashi Sakamoto 		err = -EINVAL;
202eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0b) /* IN TRANSITION */
203eb7b3a05STakashi Sakamoto 		err = -EAGAIN;
204eb7b3a05STakashi Sakamoto 	if (err < 0)
205eb7b3a05STakashi Sakamoto 		goto end;
206eb7b3a05STakashi Sakamoto 
207eb7b3a05STakashi Sakamoto 	/* Pick up specific data. */
208eb7b3a05STakashi Sakamoto 	memmove(buf, buf + 10, err - 10);
209eb7b3a05STakashi Sakamoto 	err = 0;
210eb7b3a05STakashi Sakamoto end:
211eb7b3a05STakashi Sakamoto 	return err;
212eb7b3a05STakashi Sakamoto }
213eb7b3a05STakashi Sakamoto 
avc_bridgeco_get_plug_section_type(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],unsigned int id,u8 * type)214eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
215eb7b3a05STakashi Sakamoto 				       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
216eb7b3a05STakashi Sakamoto 				       unsigned int id, u8 *type)
217eb7b3a05STakashi Sakamoto {
218eb7b3a05STakashi Sakamoto 	u8 *buf;
219eb7b3a05STakashi Sakamoto 	int err;
220eb7b3a05STakashi Sakamoto 
221eb7b3a05STakashi Sakamoto 	/* section info includes charactors but this module don't need it */
222eb7b3a05STakashi Sakamoto 	buf = kzalloc(12, GFP_KERNEL);
223eb7b3a05STakashi Sakamoto 	if (buf == NULL)
224eb7b3a05STakashi Sakamoto 		return -ENOMEM;
225eb7b3a05STakashi Sakamoto 
226eb7b3a05STakashi Sakamoto 	/* Info type is 'section info'. */
227eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07);
228eb7b3a05STakashi Sakamoto 	buf[10] = 0xff & ++id;	/* section id */
229eb7b3a05STakashi Sakamoto 
230eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
231eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
232eb7b3a05STakashi Sakamoto 				  BIT(6) | BIT(7) | BIT(9) | BIT(10));
2337e1621deSTakashi Sakamoto 	if (err < 0)
2347e1621deSTakashi Sakamoto 		;
2357e1621deSTakashi Sakamoto 	else if (err < 12)
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 	*type = buf[11];
247eb7b3a05STakashi Sakamoto 	err = 0;
248eb7b3a05STakashi Sakamoto end:
249eb7b3a05STakashi Sakamoto 	kfree(buf);
250eb7b3a05STakashi Sakamoto 	return err;
251eb7b3a05STakashi Sakamoto }
252eb7b3a05STakashi Sakamoto 
avc_bridgeco_get_plug_input(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],u8 input[7])253eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_input(struct fw_unit *unit,
254eb7b3a05STakashi Sakamoto 				u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7])
255eb7b3a05STakashi Sakamoto {
256eb7b3a05STakashi Sakamoto 	int err;
257eb7b3a05STakashi Sakamoto 	u8 *buf;
258eb7b3a05STakashi Sakamoto 
259eb7b3a05STakashi Sakamoto 	buf = kzalloc(18, GFP_KERNEL);
260eb7b3a05STakashi Sakamoto 	if (buf == NULL)
261eb7b3a05STakashi Sakamoto 		return -ENOMEM;
262eb7b3a05STakashi Sakamoto 
263eb7b3a05STakashi Sakamoto 	/* Info type is 'plug input'. */
264eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05);
265eb7b3a05STakashi Sakamoto 
266eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 16, buf, 16,
267eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
268eb7b3a05STakashi Sakamoto 				  BIT(6) | BIT(7));
2697e1621deSTakashi Sakamoto 	if (err < 0)
2707e1621deSTakashi Sakamoto 		;
2717e1621deSTakashi Sakamoto 	else if (err < 16)
272eb7b3a05STakashi Sakamoto 		err = -EIO;
273eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
274eb7b3a05STakashi Sakamoto 		err = -ENOSYS;
275eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0a) /* REJECTED */
276eb7b3a05STakashi Sakamoto 		err = -EINVAL;
277eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0b) /* IN TRANSITION */
278eb7b3a05STakashi Sakamoto 		err = -EAGAIN;
279eb7b3a05STakashi Sakamoto 	if (err < 0)
280eb7b3a05STakashi Sakamoto 		goto end;
281eb7b3a05STakashi Sakamoto 
282eb7b3a05STakashi Sakamoto 	memcpy(input, buf + 10, 5);
283eb7b3a05STakashi Sakamoto 	err = 0;
284eb7b3a05STakashi Sakamoto end:
285eb7b3a05STakashi Sakamoto 	kfree(buf);
286eb7b3a05STakashi Sakamoto 	return err;
287eb7b3a05STakashi Sakamoto }
288eb7b3a05STakashi Sakamoto 
avc_bridgeco_get_plug_strm_fmt(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],u8 * buf,unsigned int * len,unsigned int eid)289eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
290eb7b3a05STakashi Sakamoto 				   u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf,
291eb7b3a05STakashi Sakamoto 				   unsigned int *len, unsigned int eid)
292eb7b3a05STakashi Sakamoto {
293eb7b3a05STakashi Sakamoto 	int err;
294eb7b3a05STakashi Sakamoto 
295eb7b3a05STakashi Sakamoto 	/* check given buffer */
296eb7b3a05STakashi Sakamoto 	if ((buf == NULL) || (*len < 12)) {
297eb7b3a05STakashi Sakamoto 		err = -EINVAL;
298eb7b3a05STakashi Sakamoto 		goto end;
299eb7b3a05STakashi Sakamoto 	}
300eb7b3a05STakashi Sakamoto 
301eb7b3a05STakashi Sakamoto 	buf[0] = 0x01;	/* AV/C STATUS */
302eb7b3a05STakashi Sakamoto 	buf[2] = 0x2f;	/* AV/C STREAM FORMAT SUPPORT */
303eb7b3a05STakashi Sakamoto 	buf[3] = 0xc1;	/* Bridgeco extension - List Request */
304eb7b3a05STakashi Sakamoto 	avc_bridgeco_fill_extension_addr(buf, addr);
305eb7b3a05STakashi Sakamoto 	buf[10] = 0xff & eid;	/* Entry ID */
306eb7b3a05STakashi Sakamoto 
307eb7b3a05STakashi Sakamoto 	err = fcp_avc_transaction(unit, buf, 12, buf, *len,
308eb7b3a05STakashi Sakamoto 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
309eb7b3a05STakashi Sakamoto 				  BIT(6) | BIT(7) | BIT(10));
3107e1621deSTakashi Sakamoto 	if (err < 0)
3117e1621deSTakashi Sakamoto 		;
3127e1621deSTakashi Sakamoto 	else if (err < 12)
313eb7b3a05STakashi Sakamoto 		err = -EIO;
314eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x08)        /* NOT IMPLEMENTED */
315eb7b3a05STakashi Sakamoto 		err = -ENOSYS;
316eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0a)        /* REJECTED */
317eb7b3a05STakashi Sakamoto 		err = -EINVAL;
318eb7b3a05STakashi Sakamoto 	else if (buf[0] == 0x0b)        /* IN TRANSITION */
319eb7b3a05STakashi Sakamoto 		err = -EAGAIN;
320eb7b3a05STakashi Sakamoto 	else if (buf[10] != eid)
321eb7b3a05STakashi Sakamoto 		err = -EIO;
322eb7b3a05STakashi Sakamoto 	if (err < 0)
323eb7b3a05STakashi Sakamoto 		goto end;
324eb7b3a05STakashi Sakamoto 
325eb7b3a05STakashi Sakamoto 	/* Pick up 'stream format info'. */
326eb7b3a05STakashi Sakamoto 	memmove(buf, buf + 11, err - 11);
327eb7b3a05STakashi Sakamoto 	*len = err - 11;
328eb7b3a05STakashi Sakamoto 	err = 0;
329eb7b3a05STakashi Sakamoto end:
330eb7b3a05STakashi Sakamoto 	return err;
331eb7b3a05STakashi Sakamoto }
332