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