diff options
Diffstat (limited to 'sound/firewire/bebob/bebob_command.c')
-rw-r--r-- | sound/firewire/bebob/bebob_command.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/sound/firewire/bebob/bebob_command.c b/sound/firewire/bebob/bebob_command.c new file mode 100644 index 000000000000..9402cc15dbc1 --- /dev/null +++ b/sound/firewire/bebob/bebob_command.c | |||
@@ -0,0 +1,282 @@ | |||
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 | } | ||