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_pos(struct fw_unit *unit, 147 u8 addr[AVC_BRIDGECO_ADDR_BYTES], 148 u8 *buf, unsigned int len) 149 { 150 int err; 151 152 /* Info type is 'channel position'. */ 153 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03); 154 155 err = fcp_avc_transaction(unit, buf, 12, buf, 256, 156 BIT(1) | BIT(2) | BIT(3) | BIT(4) | 157 BIT(5) | BIT(6) | BIT(7) | BIT(9)); 158 if (err < 0) 159 ; 160 else if (err < 11) 161 err = -EIO; 162 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 163 err = -ENOSYS; 164 else if (buf[0] == 0x0a) /* REJECTED */ 165 err = -EINVAL; 166 else if (buf[0] == 0x0b) /* IN TRANSITION */ 167 err = -EAGAIN; 168 if (err < 0) 169 goto end; 170 171 /* Pick up specific data. */ 172 memmove(buf, buf + 10, err - 10); 173 err = 0; 174 end: 175 return err; 176 } 177 178 int avc_bridgeco_get_plug_section_type(struct fw_unit *unit, 179 u8 addr[AVC_BRIDGECO_ADDR_BYTES], 180 unsigned int id, u8 *type) 181 { 182 u8 *buf; 183 int err; 184 185 /* section info includes charactors but this module don't need it */ 186 buf = kzalloc(12, GFP_KERNEL); 187 if (buf == NULL) 188 return -ENOMEM; 189 190 /* Info type is 'section info'. */ 191 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07); 192 buf[10] = 0xff & ++id; /* section id */ 193 194 err = fcp_avc_transaction(unit, buf, 12, buf, 12, 195 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 196 BIT(6) | BIT(7) | BIT(9) | BIT(10)); 197 if (err < 0) 198 ; 199 else if (err < 12) 200 err = -EIO; 201 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 202 err = -ENOSYS; 203 else if (buf[0] == 0x0a) /* REJECTED */ 204 err = -EINVAL; 205 else if (buf[0] == 0x0b) /* IN TRANSITION */ 206 err = -EAGAIN; 207 if (err < 0) 208 goto end; 209 210 *type = buf[11]; 211 err = 0; 212 end: 213 kfree(buf); 214 return err; 215 } 216 217 int avc_bridgeco_get_plug_input(struct fw_unit *unit, 218 u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7]) 219 { 220 int err; 221 u8 *buf; 222 223 buf = kzalloc(18, GFP_KERNEL); 224 if (buf == NULL) 225 return -ENOMEM; 226 227 /* Info type is 'plug input'. */ 228 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05); 229 230 err = fcp_avc_transaction(unit, buf, 16, buf, 16, 231 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 232 BIT(6) | BIT(7)); 233 if (err < 0) 234 ; 235 else if (err < 16) 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 memcpy(input, buf + 10, 5); 247 err = 0; 248 end: 249 kfree(buf); 250 return err; 251 } 252 253 int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit, 254 u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf, 255 unsigned int *len, unsigned int eid) 256 { 257 int err; 258 259 /* check given buffer */ 260 if ((buf == NULL) || (*len < 12)) { 261 err = -EINVAL; 262 goto end; 263 } 264 265 buf[0] = 0x01; /* AV/C STATUS */ 266 buf[2] = 0x2f; /* AV/C STREAM FORMAT SUPPORT */ 267 buf[3] = 0xc1; /* Bridgeco extension - List Request */ 268 avc_bridgeco_fill_extension_addr(buf, addr); 269 buf[10] = 0xff & eid; /* Entry ID */ 270 271 err = fcp_avc_transaction(unit, buf, 12, buf, *len, 272 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 273 BIT(6) | BIT(7) | BIT(10)); 274 if (err < 0) 275 ; 276 else if (err < 12) 277 err = -EIO; 278 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 279 err = -ENOSYS; 280 else if (buf[0] == 0x0a) /* REJECTED */ 281 err = -EINVAL; 282 else if (buf[0] == 0x0b) /* IN TRANSITION */ 283 err = -EAGAIN; 284 else if (buf[10] != eid) 285 err = -EIO; 286 if (err < 0) 287 goto end; 288 289 /* Pick up 'stream format info'. */ 290 memmove(buf, buf + 11, err - 11); 291 *len = err - 11; 292 err = 0; 293 end: 294 return err; 295 } 296