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