332 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * bebob_command.c - driver for BeBoB based devices4 *5 * Copyright (c) 2013-2014 Takashi Sakamoto6 */7 8#include "./bebob.h"9 10int 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 else42 err = 0;43 44 kfree(buf);45 return err;46}47 48int 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;86end:87 kfree(buf);88 return err;89}90 91static inline void92avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr)93{94 buf[1] = addr[0];95 memcpy(buf + 4, addr + 1, 5);96}97 98static inline void99avc_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 109int 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;141end:142 kfree(buf);143 return err;144}145 146int 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 IMPLEMENTED167 err = -ENOSYS;168 else if (buf[0] == 0x0a) // REJECTED169 err = -EINVAL;170 else if (buf[0] == 0x0b) // IN TRANSITION171 err = -EAGAIN;172 if (err < 0)173 goto end;174 175 *ch_count = buf[10];176 err = 0;177end:178 kfree(buf);179 return err;180}181 182int 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;210end:211 return err;212}213 214int 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;248end:249 kfree(buf);250 return err;251}252 253int 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;284end:285 kfree(buf);286 return err;287}288 289int 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;329end:330 return err;331}332