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