1*da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2eb7b3a05STakashi Sakamoto /* 3eb7b3a05STakashi Sakamoto * bebob_command.c - driver for BeBoB based devices 4eb7b3a05STakashi Sakamoto * 5eb7b3a05STakashi Sakamoto * Copyright (c) 2013-2014 Takashi Sakamoto 6eb7b3a05STakashi Sakamoto */ 7eb7b3a05STakashi Sakamoto 8eb7b3a05STakashi Sakamoto #include "./bebob.h" 9eb7b3a05STakashi Sakamoto 101fc9522aSTakashi Sakamoto int avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id, 111fc9522aSTakashi Sakamoto unsigned int fb_id, unsigned int num) 121fc9522aSTakashi Sakamoto { 131fc9522aSTakashi Sakamoto u8 *buf; 141fc9522aSTakashi Sakamoto int err; 151fc9522aSTakashi Sakamoto 161fc9522aSTakashi Sakamoto buf = kzalloc(12, GFP_KERNEL); 171fc9522aSTakashi Sakamoto if (buf == NULL) 181fc9522aSTakashi Sakamoto return -ENOMEM; 191fc9522aSTakashi Sakamoto 201fc9522aSTakashi Sakamoto buf[0] = 0x00; /* AV/C CONTROL */ 211fc9522aSTakashi Sakamoto buf[1] = 0x08 | (0x07 & subunit_id); /* AUDIO SUBUNIT ID */ 221fc9522aSTakashi Sakamoto buf[2] = 0xb8; /* FUNCTION BLOCK */ 231fc9522aSTakashi Sakamoto buf[3] = 0x80; /* type is 'selector'*/ 241fc9522aSTakashi Sakamoto buf[4] = 0xff & fb_id; /* function block id */ 251fc9522aSTakashi Sakamoto buf[5] = 0x10; /* control attribute is CURRENT */ 261fc9522aSTakashi Sakamoto buf[6] = 0x02; /* selector length is 2 */ 271fc9522aSTakashi Sakamoto buf[7] = 0xff & num; /* input function block plug number */ 281fc9522aSTakashi Sakamoto buf[8] = 0x01; /* control selector is SELECTOR_CONTROL */ 291fc9522aSTakashi Sakamoto 301fc9522aSTakashi Sakamoto err = fcp_avc_transaction(unit, buf, 12, buf, 12, 311fc9522aSTakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 321fc9522aSTakashi Sakamoto BIT(6) | BIT(7) | BIT(8)); 337e1621deSTakashi Sakamoto if (err < 0) 347e1621deSTakashi Sakamoto ; 357e1621deSTakashi Sakamoto else if (err < 9) 361fc9522aSTakashi Sakamoto err = -EIO; 371fc9522aSTakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 381fc9522aSTakashi Sakamoto err = -ENOSYS; 391fc9522aSTakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 401fc9522aSTakashi Sakamoto err = -EINVAL; 417e1621deSTakashi Sakamoto else 421fc9522aSTakashi Sakamoto err = 0; 431fc9522aSTakashi Sakamoto 441fc9522aSTakashi Sakamoto kfree(buf); 451fc9522aSTakashi Sakamoto return err; 461fc9522aSTakashi Sakamoto } 471fc9522aSTakashi Sakamoto 481fc9522aSTakashi Sakamoto int avc_audio_get_selector(struct fw_unit *unit, unsigned int subunit_id, 491fc9522aSTakashi Sakamoto unsigned int fb_id, unsigned int *num) 501fc9522aSTakashi Sakamoto { 511fc9522aSTakashi Sakamoto u8 *buf; 521fc9522aSTakashi Sakamoto int err; 531fc9522aSTakashi Sakamoto 541fc9522aSTakashi Sakamoto buf = kzalloc(12, GFP_KERNEL); 551fc9522aSTakashi Sakamoto if (buf == NULL) 561fc9522aSTakashi Sakamoto return -ENOMEM; 571fc9522aSTakashi Sakamoto 581fc9522aSTakashi Sakamoto buf[0] = 0x01; /* AV/C STATUS */ 591fc9522aSTakashi Sakamoto buf[1] = 0x08 | (0x07 & subunit_id); /* AUDIO SUBUNIT ID */ 601fc9522aSTakashi Sakamoto buf[2] = 0xb8; /* FUNCTION BLOCK */ 611fc9522aSTakashi Sakamoto buf[3] = 0x80; /* type is 'selector'*/ 621fc9522aSTakashi Sakamoto buf[4] = 0xff & fb_id; /* function block id */ 631fc9522aSTakashi Sakamoto buf[5] = 0x10; /* control attribute is CURRENT */ 641fc9522aSTakashi Sakamoto buf[6] = 0x02; /* selector length is 2 */ 651fc9522aSTakashi Sakamoto buf[7] = 0xff; /* input function block plug number */ 661fc9522aSTakashi Sakamoto buf[8] = 0x01; /* control selector is SELECTOR_CONTROL */ 671fc9522aSTakashi Sakamoto 681fc9522aSTakashi Sakamoto err = fcp_avc_transaction(unit, buf, 12, buf, 12, 691fc9522aSTakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 701fc9522aSTakashi Sakamoto BIT(6) | BIT(8)); 717e1621deSTakashi Sakamoto if (err < 0) 727e1621deSTakashi Sakamoto ; 737e1621deSTakashi Sakamoto else if (err < 9) 741fc9522aSTakashi Sakamoto err = -EIO; 751fc9522aSTakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 761fc9522aSTakashi Sakamoto err = -ENOSYS; 771fc9522aSTakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 781fc9522aSTakashi Sakamoto err = -EINVAL; 791fc9522aSTakashi Sakamoto else if (buf[0] == 0x0b) /* IN TRANSITION */ 801fc9522aSTakashi Sakamoto err = -EAGAIN; 811fc9522aSTakashi Sakamoto if (err < 0) 821fc9522aSTakashi Sakamoto goto end; 831fc9522aSTakashi Sakamoto 841fc9522aSTakashi Sakamoto *num = buf[7]; 851fc9522aSTakashi Sakamoto err = 0; 861fc9522aSTakashi Sakamoto end: 871fc9522aSTakashi Sakamoto kfree(buf); 881fc9522aSTakashi Sakamoto return err; 891fc9522aSTakashi Sakamoto } 901fc9522aSTakashi Sakamoto 91eb7b3a05STakashi Sakamoto static inline void 92eb7b3a05STakashi Sakamoto avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr) 93eb7b3a05STakashi Sakamoto { 94eb7b3a05STakashi Sakamoto buf[1] = addr[0]; 95eb7b3a05STakashi Sakamoto memcpy(buf + 4, addr + 1, 5); 96eb7b3a05STakashi Sakamoto } 97eb7b3a05STakashi Sakamoto 98eb7b3a05STakashi Sakamoto static inline void 99eb7b3a05STakashi Sakamoto avc_bridgeco_fill_plug_info_extension_command(u8 *buf, u8 *addr, 100eb7b3a05STakashi Sakamoto unsigned int itype) 101eb7b3a05STakashi Sakamoto { 102eb7b3a05STakashi Sakamoto buf[0] = 0x01; /* AV/C STATUS */ 103eb7b3a05STakashi Sakamoto buf[2] = 0x02; /* AV/C GENERAL PLUG INFO */ 104eb7b3a05STakashi Sakamoto buf[3] = 0xc0; /* BridgeCo extension */ 105eb7b3a05STakashi Sakamoto avc_bridgeco_fill_extension_addr(buf, addr); 106eb7b3a05STakashi Sakamoto buf[9] = itype; /* info type */ 107eb7b3a05STakashi Sakamoto } 108eb7b3a05STakashi Sakamoto 109eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_type(struct fw_unit *unit, 110eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], 111eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_type *type) 112eb7b3a05STakashi Sakamoto { 113eb7b3a05STakashi Sakamoto u8 *buf; 114eb7b3a05STakashi Sakamoto int err; 115eb7b3a05STakashi Sakamoto 116eb7b3a05STakashi Sakamoto buf = kzalloc(12, GFP_KERNEL); 117eb7b3a05STakashi Sakamoto if (buf == NULL) 118eb7b3a05STakashi Sakamoto return -ENOMEM; 119eb7b3a05STakashi Sakamoto 120eb7b3a05STakashi Sakamoto /* Info type is 'plug type'. */ 121eb7b3a05STakashi Sakamoto avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x00); 122eb7b3a05STakashi Sakamoto 123eb7b3a05STakashi Sakamoto err = fcp_avc_transaction(unit, buf, 12, buf, 12, 124eb7b3a05STakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 125eb7b3a05STakashi Sakamoto BIT(6) | BIT(7) | BIT(9)); 1267e1621deSTakashi Sakamoto if (err < 0) 1277e1621deSTakashi Sakamoto ; 1287e1621deSTakashi Sakamoto else if (err < 11) 129eb7b3a05STakashi Sakamoto err = -EIO; 130eb7b3a05STakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 131eb7b3a05STakashi Sakamoto err = -ENOSYS; 132eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 133eb7b3a05STakashi Sakamoto err = -EINVAL; 134eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0b) /* IN TRANSITION */ 135eb7b3a05STakashi Sakamoto err = -EAGAIN; 136eb7b3a05STakashi Sakamoto if (err < 0) 137eb7b3a05STakashi Sakamoto goto end; 138eb7b3a05STakashi Sakamoto 139eb7b3a05STakashi Sakamoto *type = buf[10]; 140eb7b3a05STakashi Sakamoto err = 0; 141eb7b3a05STakashi Sakamoto end: 142eb7b3a05STakashi Sakamoto kfree(buf); 143eb7b3a05STakashi Sakamoto return err; 144eb7b3a05STakashi Sakamoto } 145eb7b3a05STakashi Sakamoto 146eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, 147eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], 148eb7b3a05STakashi Sakamoto u8 *buf, unsigned int len) 149eb7b3a05STakashi Sakamoto { 150eb7b3a05STakashi Sakamoto int err; 151eb7b3a05STakashi Sakamoto 152eb7b3a05STakashi Sakamoto /* Info type is 'channel position'. */ 153eb7b3a05STakashi Sakamoto avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03); 154eb7b3a05STakashi Sakamoto 155eb7b3a05STakashi Sakamoto err = fcp_avc_transaction(unit, buf, 12, buf, 256, 156eb7b3a05STakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4) | 157eb7b3a05STakashi Sakamoto BIT(5) | BIT(6) | BIT(7) | BIT(9)); 1587e1621deSTakashi Sakamoto if (err < 0) 1597e1621deSTakashi Sakamoto ; 1607e1621deSTakashi Sakamoto else if (err < 11) 161eb7b3a05STakashi Sakamoto err = -EIO; 162eb7b3a05STakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 163eb7b3a05STakashi Sakamoto err = -ENOSYS; 164eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 165eb7b3a05STakashi Sakamoto err = -EINVAL; 166eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0b) /* IN TRANSITION */ 167eb7b3a05STakashi Sakamoto err = -EAGAIN; 168eb7b3a05STakashi Sakamoto if (err < 0) 169eb7b3a05STakashi Sakamoto goto end; 170eb7b3a05STakashi Sakamoto 171eb7b3a05STakashi Sakamoto /* Pick up specific data. */ 172eb7b3a05STakashi Sakamoto memmove(buf, buf + 10, err - 10); 173eb7b3a05STakashi Sakamoto err = 0; 174eb7b3a05STakashi Sakamoto end: 175eb7b3a05STakashi Sakamoto return err; 176eb7b3a05STakashi Sakamoto } 177eb7b3a05STakashi Sakamoto 178eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_section_type(struct fw_unit *unit, 179eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], 180eb7b3a05STakashi Sakamoto unsigned int id, u8 *type) 181eb7b3a05STakashi Sakamoto { 182eb7b3a05STakashi Sakamoto u8 *buf; 183eb7b3a05STakashi Sakamoto int err; 184eb7b3a05STakashi Sakamoto 185eb7b3a05STakashi Sakamoto /* section info includes charactors but this module don't need it */ 186eb7b3a05STakashi Sakamoto buf = kzalloc(12, GFP_KERNEL); 187eb7b3a05STakashi Sakamoto if (buf == NULL) 188eb7b3a05STakashi Sakamoto return -ENOMEM; 189eb7b3a05STakashi Sakamoto 190eb7b3a05STakashi Sakamoto /* Info type is 'section info'. */ 191eb7b3a05STakashi Sakamoto avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07); 192eb7b3a05STakashi Sakamoto buf[10] = 0xff & ++id; /* section id */ 193eb7b3a05STakashi Sakamoto 194eb7b3a05STakashi Sakamoto err = fcp_avc_transaction(unit, buf, 12, buf, 12, 195eb7b3a05STakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 196eb7b3a05STakashi Sakamoto BIT(6) | BIT(7) | BIT(9) | BIT(10)); 1977e1621deSTakashi Sakamoto if (err < 0) 1987e1621deSTakashi Sakamoto ; 1997e1621deSTakashi Sakamoto else if (err < 12) 200eb7b3a05STakashi Sakamoto err = -EIO; 201eb7b3a05STakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 202eb7b3a05STakashi Sakamoto err = -ENOSYS; 203eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 204eb7b3a05STakashi Sakamoto err = -EINVAL; 205eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0b) /* IN TRANSITION */ 206eb7b3a05STakashi Sakamoto err = -EAGAIN; 207eb7b3a05STakashi Sakamoto if (err < 0) 208eb7b3a05STakashi Sakamoto goto end; 209eb7b3a05STakashi Sakamoto 210eb7b3a05STakashi Sakamoto *type = buf[11]; 211eb7b3a05STakashi Sakamoto err = 0; 212eb7b3a05STakashi Sakamoto end: 213eb7b3a05STakashi Sakamoto kfree(buf); 214eb7b3a05STakashi Sakamoto return err; 215eb7b3a05STakashi Sakamoto } 216eb7b3a05STakashi Sakamoto 217eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_input(struct fw_unit *unit, 218eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7]) 219eb7b3a05STakashi Sakamoto { 220eb7b3a05STakashi Sakamoto int err; 221eb7b3a05STakashi Sakamoto u8 *buf; 222eb7b3a05STakashi Sakamoto 223eb7b3a05STakashi Sakamoto buf = kzalloc(18, GFP_KERNEL); 224eb7b3a05STakashi Sakamoto if (buf == NULL) 225eb7b3a05STakashi Sakamoto return -ENOMEM; 226eb7b3a05STakashi Sakamoto 227eb7b3a05STakashi Sakamoto /* Info type is 'plug input'. */ 228eb7b3a05STakashi Sakamoto avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05); 229eb7b3a05STakashi Sakamoto 230eb7b3a05STakashi Sakamoto err = fcp_avc_transaction(unit, buf, 16, buf, 16, 231eb7b3a05STakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 232eb7b3a05STakashi Sakamoto BIT(6) | BIT(7)); 2337e1621deSTakashi Sakamoto if (err < 0) 2347e1621deSTakashi Sakamoto ; 2357e1621deSTakashi Sakamoto else if (err < 16) 236eb7b3a05STakashi Sakamoto err = -EIO; 237eb7b3a05STakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 238eb7b3a05STakashi Sakamoto err = -ENOSYS; 239eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 240eb7b3a05STakashi Sakamoto err = -EINVAL; 241eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0b) /* IN TRANSITION */ 242eb7b3a05STakashi Sakamoto err = -EAGAIN; 243eb7b3a05STakashi Sakamoto if (err < 0) 244eb7b3a05STakashi Sakamoto goto end; 245eb7b3a05STakashi Sakamoto 246eb7b3a05STakashi Sakamoto memcpy(input, buf + 10, 5); 247eb7b3a05STakashi Sakamoto err = 0; 248eb7b3a05STakashi Sakamoto end: 249eb7b3a05STakashi Sakamoto kfree(buf); 250eb7b3a05STakashi Sakamoto return err; 251eb7b3a05STakashi Sakamoto } 252eb7b3a05STakashi Sakamoto 253eb7b3a05STakashi Sakamoto int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit, 254eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf, 255eb7b3a05STakashi Sakamoto unsigned int *len, unsigned int eid) 256eb7b3a05STakashi Sakamoto { 257eb7b3a05STakashi Sakamoto int err; 258eb7b3a05STakashi Sakamoto 259eb7b3a05STakashi Sakamoto /* check given buffer */ 260eb7b3a05STakashi Sakamoto if ((buf == NULL) || (*len < 12)) { 261eb7b3a05STakashi Sakamoto err = -EINVAL; 262eb7b3a05STakashi Sakamoto goto end; 263eb7b3a05STakashi Sakamoto } 264eb7b3a05STakashi Sakamoto 265eb7b3a05STakashi Sakamoto buf[0] = 0x01; /* AV/C STATUS */ 266eb7b3a05STakashi Sakamoto buf[2] = 0x2f; /* AV/C STREAM FORMAT SUPPORT */ 267eb7b3a05STakashi Sakamoto buf[3] = 0xc1; /* Bridgeco extension - List Request */ 268eb7b3a05STakashi Sakamoto avc_bridgeco_fill_extension_addr(buf, addr); 269eb7b3a05STakashi Sakamoto buf[10] = 0xff & eid; /* Entry ID */ 270eb7b3a05STakashi Sakamoto 271eb7b3a05STakashi Sakamoto err = fcp_avc_transaction(unit, buf, 12, buf, *len, 272eb7b3a05STakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 273eb7b3a05STakashi Sakamoto BIT(6) | BIT(7) | BIT(10)); 2747e1621deSTakashi Sakamoto if (err < 0) 2757e1621deSTakashi Sakamoto ; 2767e1621deSTakashi Sakamoto else if (err < 12) 277eb7b3a05STakashi Sakamoto err = -EIO; 278eb7b3a05STakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 279eb7b3a05STakashi Sakamoto err = -ENOSYS; 280eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 281eb7b3a05STakashi Sakamoto err = -EINVAL; 282eb7b3a05STakashi Sakamoto else if (buf[0] == 0x0b) /* IN TRANSITION */ 283eb7b3a05STakashi Sakamoto err = -EAGAIN; 284eb7b3a05STakashi Sakamoto else if (buf[10] != eid) 285eb7b3a05STakashi Sakamoto err = -EIO; 286eb7b3a05STakashi Sakamoto if (err < 0) 287eb7b3a05STakashi Sakamoto goto end; 288eb7b3a05STakashi Sakamoto 289eb7b3a05STakashi Sakamoto /* Pick up 'stream format info'. */ 290eb7b3a05STakashi Sakamoto memmove(buf, buf + 11, err - 11); 291eb7b3a05STakashi Sakamoto *len = err - 11; 292eb7b3a05STakashi Sakamoto err = 0; 293eb7b3a05STakashi Sakamoto end: 294eb7b3a05STakashi Sakamoto return err; 295eb7b3a05STakashi Sakamoto } 296