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