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