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