xref: /OK3568_Linux_fs/kernel/sound/firewire/bebob/bebob_command.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * bebob_command.c - driver for BeBoB based devices
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2013-2014 Takashi Sakamoto
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "./bebob.h"
9*4882a593Smuzhiyun 
avc_audio_set_selector(struct fw_unit * unit,unsigned int subunit_id,unsigned int fb_id,unsigned int num)10*4882a593Smuzhiyun int avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id,
11*4882a593Smuzhiyun 			   unsigned int fb_id, unsigned int num)
12*4882a593Smuzhiyun {
13*4882a593Smuzhiyun 	u8 *buf;
14*4882a593Smuzhiyun 	int err;
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun 	buf = kzalloc(12, GFP_KERNEL);
17*4882a593Smuzhiyun 	if (buf == NULL)
18*4882a593Smuzhiyun 		return -ENOMEM;
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	buf[0]  = 0x00;		/* AV/C CONTROL */
21*4882a593Smuzhiyun 	buf[1]  = 0x08 | (0x07 & subunit_id);	/* AUDIO SUBUNIT ID */
22*4882a593Smuzhiyun 	buf[2]  = 0xb8;		/* FUNCTION BLOCK  */
23*4882a593Smuzhiyun 	buf[3]  = 0x80;		/* type is 'selector'*/
24*4882a593Smuzhiyun 	buf[4]  = 0xff & fb_id;	/* function block id */
25*4882a593Smuzhiyun 	buf[5]  = 0x10;		/* control attribute is CURRENT */
26*4882a593Smuzhiyun 	buf[6]  = 0x02;		/* selector length is 2 */
27*4882a593Smuzhiyun 	buf[7]  = 0xff & num;	/* input function block plug number */
28*4882a593Smuzhiyun 	buf[8]  = 0x01;		/* control selector is SELECTOR_CONTROL */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
31*4882a593Smuzhiyun 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
32*4882a593Smuzhiyun 				  BIT(6) | BIT(7) | BIT(8));
33*4882a593Smuzhiyun 	if (err < 0)
34*4882a593Smuzhiyun 		;
35*4882a593Smuzhiyun 	else if (err < 9)
36*4882a593Smuzhiyun 		err = -EIO;
37*4882a593Smuzhiyun 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
38*4882a593Smuzhiyun 		err = -ENOSYS;
39*4882a593Smuzhiyun 	else if (buf[0] == 0x0a) /* REJECTED */
40*4882a593Smuzhiyun 		err = -EINVAL;
41*4882a593Smuzhiyun 	else
42*4882a593Smuzhiyun 		err = 0;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	kfree(buf);
45*4882a593Smuzhiyun 	return err;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
avc_audio_get_selector(struct fw_unit * unit,unsigned int subunit_id,unsigned int fb_id,unsigned int * num)48*4882a593Smuzhiyun int avc_audio_get_selector(struct fw_unit *unit, unsigned int subunit_id,
49*4882a593Smuzhiyun 			   unsigned int fb_id, unsigned int *num)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	u8 *buf;
52*4882a593Smuzhiyun 	int err;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	buf = kzalloc(12, GFP_KERNEL);
55*4882a593Smuzhiyun 	if (buf == NULL)
56*4882a593Smuzhiyun 		return -ENOMEM;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	buf[0]  = 0x01;		/* AV/C STATUS */
59*4882a593Smuzhiyun 	buf[1]  = 0x08 | (0x07 & subunit_id);	/* AUDIO SUBUNIT ID */
60*4882a593Smuzhiyun 	buf[2]  = 0xb8;		/* FUNCTION BLOCK */
61*4882a593Smuzhiyun 	buf[3]  = 0x80;		/* type is 'selector'*/
62*4882a593Smuzhiyun 	buf[4]  = 0xff & fb_id;	/* function block id */
63*4882a593Smuzhiyun 	buf[5]  = 0x10;		/* control attribute is CURRENT */
64*4882a593Smuzhiyun 	buf[6]  = 0x02;		/* selector length is 2 */
65*4882a593Smuzhiyun 	buf[7]  = 0xff;		/* input function block plug number */
66*4882a593Smuzhiyun 	buf[8]  = 0x01;		/* control selector is SELECTOR_CONTROL */
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
69*4882a593Smuzhiyun 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
70*4882a593Smuzhiyun 				  BIT(6) | BIT(8));
71*4882a593Smuzhiyun 	if (err < 0)
72*4882a593Smuzhiyun 		;
73*4882a593Smuzhiyun 	else if (err < 9)
74*4882a593Smuzhiyun 		err = -EIO;
75*4882a593Smuzhiyun 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
76*4882a593Smuzhiyun 		err = -ENOSYS;
77*4882a593Smuzhiyun 	else if (buf[0] == 0x0a) /* REJECTED */
78*4882a593Smuzhiyun 		err = -EINVAL;
79*4882a593Smuzhiyun 	else if (buf[0] == 0x0b) /* IN TRANSITION */
80*4882a593Smuzhiyun 		err = -EAGAIN;
81*4882a593Smuzhiyun 	if (err < 0)
82*4882a593Smuzhiyun 		goto end;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	*num = buf[7];
85*4882a593Smuzhiyun 	err = 0;
86*4882a593Smuzhiyun end:
87*4882a593Smuzhiyun 	kfree(buf);
88*4882a593Smuzhiyun 	return err;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static inline void
avc_bridgeco_fill_extension_addr(u8 * buf,u8 * addr)92*4882a593Smuzhiyun avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	buf[1] = addr[0];
95*4882a593Smuzhiyun 	memcpy(buf + 4, addr + 1, 5);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun static inline void
avc_bridgeco_fill_plug_info_extension_command(u8 * buf,u8 * addr,unsigned int itype)99*4882a593Smuzhiyun avc_bridgeco_fill_plug_info_extension_command(u8 *buf, u8 *addr,
100*4882a593Smuzhiyun 					      unsigned int itype)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	buf[0] = 0x01;	/* AV/C STATUS */
103*4882a593Smuzhiyun 	buf[2] = 0x02;	/* AV/C GENERAL PLUG INFO */
104*4882a593Smuzhiyun 	buf[3] = 0xc0;	/* BridgeCo extension */
105*4882a593Smuzhiyun 	avc_bridgeco_fill_extension_addr(buf, addr);
106*4882a593Smuzhiyun 	buf[9] = itype;	/* info type */
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
avc_bridgeco_get_plug_type(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],enum avc_bridgeco_plug_type * type)109*4882a593Smuzhiyun int avc_bridgeco_get_plug_type(struct fw_unit *unit,
110*4882a593Smuzhiyun 			       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
111*4882a593Smuzhiyun 			       enum avc_bridgeco_plug_type *type)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	u8 *buf;
114*4882a593Smuzhiyun 	int err;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	buf = kzalloc(12, GFP_KERNEL);
117*4882a593Smuzhiyun 	if (buf == NULL)
118*4882a593Smuzhiyun 		return -ENOMEM;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	/* Info type is 'plug type'. */
121*4882a593Smuzhiyun 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x00);
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
124*4882a593Smuzhiyun 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
125*4882a593Smuzhiyun 				  BIT(6) | BIT(7) | BIT(9));
126*4882a593Smuzhiyun 	if (err < 0)
127*4882a593Smuzhiyun 		;
128*4882a593Smuzhiyun 	else if (err < 11)
129*4882a593Smuzhiyun 		err = -EIO;
130*4882a593Smuzhiyun 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
131*4882a593Smuzhiyun 		err = -ENOSYS;
132*4882a593Smuzhiyun 	else if (buf[0] == 0x0a) /* REJECTED */
133*4882a593Smuzhiyun 		err = -EINVAL;
134*4882a593Smuzhiyun 	else if (buf[0] == 0x0b) /* IN TRANSITION */
135*4882a593Smuzhiyun 		err = -EAGAIN;
136*4882a593Smuzhiyun 	if (err < 0)
137*4882a593Smuzhiyun 		goto end;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	*type = buf[10];
140*4882a593Smuzhiyun 	err = 0;
141*4882a593Smuzhiyun end:
142*4882a593Smuzhiyun 	kfree(buf);
143*4882a593Smuzhiyun 	return err;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
avc_bridgeco_get_plug_ch_pos(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],u8 * buf,unsigned int len)146*4882a593Smuzhiyun int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
147*4882a593Smuzhiyun 				 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
148*4882a593Smuzhiyun 				 u8 *buf, unsigned int len)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	int err;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/* Info type is 'channel position'. */
153*4882a593Smuzhiyun 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	err = fcp_avc_transaction(unit, buf, 12, buf, 256,
156*4882a593Smuzhiyun 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) |
157*4882a593Smuzhiyun 				  BIT(5) | BIT(6) | BIT(7) | BIT(9));
158*4882a593Smuzhiyun 	if (err < 0)
159*4882a593Smuzhiyun 		;
160*4882a593Smuzhiyun 	else if (err < 11)
161*4882a593Smuzhiyun 		err = -EIO;
162*4882a593Smuzhiyun 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
163*4882a593Smuzhiyun 		err = -ENOSYS;
164*4882a593Smuzhiyun 	else if (buf[0] == 0x0a) /* REJECTED */
165*4882a593Smuzhiyun 		err = -EINVAL;
166*4882a593Smuzhiyun 	else if (buf[0] == 0x0b) /* IN TRANSITION */
167*4882a593Smuzhiyun 		err = -EAGAIN;
168*4882a593Smuzhiyun 	if (err < 0)
169*4882a593Smuzhiyun 		goto end;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	/* Pick up specific data. */
172*4882a593Smuzhiyun 	memmove(buf, buf + 10, err - 10);
173*4882a593Smuzhiyun 	err = 0;
174*4882a593Smuzhiyun end:
175*4882a593Smuzhiyun 	return err;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
avc_bridgeco_get_plug_section_type(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],unsigned int id,u8 * type)178*4882a593Smuzhiyun int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
179*4882a593Smuzhiyun 				       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
180*4882a593Smuzhiyun 				       unsigned int id, u8 *type)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	u8 *buf;
183*4882a593Smuzhiyun 	int err;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	/* section info includes charactors but this module don't need it */
186*4882a593Smuzhiyun 	buf = kzalloc(12, GFP_KERNEL);
187*4882a593Smuzhiyun 	if (buf == NULL)
188*4882a593Smuzhiyun 		return -ENOMEM;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	/* Info type is 'section info'. */
191*4882a593Smuzhiyun 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07);
192*4882a593Smuzhiyun 	buf[10] = 0xff & ++id;	/* section id */
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
195*4882a593Smuzhiyun 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
196*4882a593Smuzhiyun 				  BIT(6) | BIT(7) | BIT(9) | BIT(10));
197*4882a593Smuzhiyun 	if (err < 0)
198*4882a593Smuzhiyun 		;
199*4882a593Smuzhiyun 	else if (err < 12)
200*4882a593Smuzhiyun 		err = -EIO;
201*4882a593Smuzhiyun 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
202*4882a593Smuzhiyun 		err = -ENOSYS;
203*4882a593Smuzhiyun 	else if (buf[0] == 0x0a) /* REJECTED */
204*4882a593Smuzhiyun 		err = -EINVAL;
205*4882a593Smuzhiyun 	else if (buf[0] == 0x0b) /* IN TRANSITION */
206*4882a593Smuzhiyun 		err = -EAGAIN;
207*4882a593Smuzhiyun 	if (err < 0)
208*4882a593Smuzhiyun 		goto end;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	*type = buf[11];
211*4882a593Smuzhiyun 	err = 0;
212*4882a593Smuzhiyun end:
213*4882a593Smuzhiyun 	kfree(buf);
214*4882a593Smuzhiyun 	return err;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
avc_bridgeco_get_plug_input(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],u8 input[7])217*4882a593Smuzhiyun int avc_bridgeco_get_plug_input(struct fw_unit *unit,
218*4882a593Smuzhiyun 				u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7])
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	int err;
221*4882a593Smuzhiyun 	u8 *buf;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	buf = kzalloc(18, GFP_KERNEL);
224*4882a593Smuzhiyun 	if (buf == NULL)
225*4882a593Smuzhiyun 		return -ENOMEM;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	/* Info type is 'plug input'. */
228*4882a593Smuzhiyun 	avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	err = fcp_avc_transaction(unit, buf, 16, buf, 16,
231*4882a593Smuzhiyun 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
232*4882a593Smuzhiyun 				  BIT(6) | BIT(7));
233*4882a593Smuzhiyun 	if (err < 0)
234*4882a593Smuzhiyun 		;
235*4882a593Smuzhiyun 	else if (err < 16)
236*4882a593Smuzhiyun 		err = -EIO;
237*4882a593Smuzhiyun 	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
238*4882a593Smuzhiyun 		err = -ENOSYS;
239*4882a593Smuzhiyun 	else if (buf[0] == 0x0a) /* REJECTED */
240*4882a593Smuzhiyun 		err = -EINVAL;
241*4882a593Smuzhiyun 	else if (buf[0] == 0x0b) /* IN TRANSITION */
242*4882a593Smuzhiyun 		err = -EAGAIN;
243*4882a593Smuzhiyun 	if (err < 0)
244*4882a593Smuzhiyun 		goto end;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	memcpy(input, buf + 10, 5);
247*4882a593Smuzhiyun 	err = 0;
248*4882a593Smuzhiyun end:
249*4882a593Smuzhiyun 	kfree(buf);
250*4882a593Smuzhiyun 	return err;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
avc_bridgeco_get_plug_strm_fmt(struct fw_unit * unit,u8 addr[AVC_BRIDGECO_ADDR_BYTES],u8 * buf,unsigned int * len,unsigned int eid)253*4882a593Smuzhiyun int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
254*4882a593Smuzhiyun 				   u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf,
255*4882a593Smuzhiyun 				   unsigned int *len, unsigned int eid)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	int err;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	/* check given buffer */
260*4882a593Smuzhiyun 	if ((buf == NULL) || (*len < 12)) {
261*4882a593Smuzhiyun 		err = -EINVAL;
262*4882a593Smuzhiyun 		goto end;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	buf[0] = 0x01;	/* AV/C STATUS */
266*4882a593Smuzhiyun 	buf[2] = 0x2f;	/* AV/C STREAM FORMAT SUPPORT */
267*4882a593Smuzhiyun 	buf[3] = 0xc1;	/* Bridgeco extension - List Request */
268*4882a593Smuzhiyun 	avc_bridgeco_fill_extension_addr(buf, addr);
269*4882a593Smuzhiyun 	buf[10] = 0xff & eid;	/* Entry ID */
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	err = fcp_avc_transaction(unit, buf, 12, buf, *len,
272*4882a593Smuzhiyun 				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
273*4882a593Smuzhiyun 				  BIT(6) | BIT(7) | BIT(10));
274*4882a593Smuzhiyun 	if (err < 0)
275*4882a593Smuzhiyun 		;
276*4882a593Smuzhiyun 	else if (err < 12)
277*4882a593Smuzhiyun 		err = -EIO;
278*4882a593Smuzhiyun 	else if (buf[0] == 0x08)        /* NOT IMPLEMENTED */
279*4882a593Smuzhiyun 		err = -ENOSYS;
280*4882a593Smuzhiyun 	else if (buf[0] == 0x0a)        /* REJECTED */
281*4882a593Smuzhiyun 		err = -EINVAL;
282*4882a593Smuzhiyun 	else if (buf[0] == 0x0b)        /* IN TRANSITION */
283*4882a593Smuzhiyun 		err = -EAGAIN;
284*4882a593Smuzhiyun 	else if (buf[10] != eid)
285*4882a593Smuzhiyun 		err = -EIO;
286*4882a593Smuzhiyun 	if (err < 0)
287*4882a593Smuzhiyun 		goto end;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/* Pick up 'stream format info'. */
290*4882a593Smuzhiyun 	memmove(buf, buf + 11, err - 11);
291*4882a593Smuzhiyun 	*len = err - 11;
292*4882a593Smuzhiyun 	err = 0;
293*4882a593Smuzhiyun end:
294*4882a593Smuzhiyun 	return err;
295*4882a593Smuzhiyun }
296