18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bebob_command.c - driver for BeBoB based devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "./bebob.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ciint avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id, 118c2ecf20Sopenharmony_ci unsigned int fb_id, unsigned int num) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci u8 *buf; 148c2ecf20Sopenharmony_ci int err; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci buf = kzalloc(12, GFP_KERNEL); 178c2ecf20Sopenharmony_ci if (buf == NULL) 188c2ecf20Sopenharmony_ci return -ENOMEM; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci buf[0] = 0x00; /* AV/C CONTROL */ 218c2ecf20Sopenharmony_ci buf[1] = 0x08 | (0x07 & subunit_id); /* AUDIO SUBUNIT ID */ 228c2ecf20Sopenharmony_ci buf[2] = 0xb8; /* FUNCTION BLOCK */ 238c2ecf20Sopenharmony_ci buf[3] = 0x80; /* type is 'selector'*/ 248c2ecf20Sopenharmony_ci buf[4] = 0xff & fb_id; /* function block id */ 258c2ecf20Sopenharmony_ci buf[5] = 0x10; /* control attribute is CURRENT */ 268c2ecf20Sopenharmony_ci buf[6] = 0x02; /* selector length is 2 */ 278c2ecf20Sopenharmony_ci buf[7] = 0xff & num; /* input function block plug number */ 288c2ecf20Sopenharmony_ci buf[8] = 0x01; /* control selector is SELECTOR_CONTROL */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci err = fcp_avc_transaction(unit, buf, 12, buf, 12, 318c2ecf20Sopenharmony_ci BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 328c2ecf20Sopenharmony_ci BIT(6) | BIT(7) | BIT(8)); 338c2ecf20Sopenharmony_ci if (err < 0) 348c2ecf20Sopenharmony_ci ; 358c2ecf20Sopenharmony_ci else if (err < 9) 368c2ecf20Sopenharmony_ci err = -EIO; 378c2ecf20Sopenharmony_ci else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 388c2ecf20Sopenharmony_ci err = -ENOSYS; 398c2ecf20Sopenharmony_ci else if (buf[0] == 0x0a) /* REJECTED */ 408c2ecf20Sopenharmony_ci err = -EINVAL; 418c2ecf20Sopenharmony_ci else 428c2ecf20Sopenharmony_ci err = 0; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci kfree(buf); 458c2ecf20Sopenharmony_ci return err; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciint avc_audio_get_selector(struct fw_unit *unit, unsigned int subunit_id, 498c2ecf20Sopenharmony_ci unsigned int fb_id, unsigned int *num) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci u8 *buf; 528c2ecf20Sopenharmony_ci int err; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci buf = kzalloc(12, GFP_KERNEL); 558c2ecf20Sopenharmony_ci if (buf == NULL) 568c2ecf20Sopenharmony_ci return -ENOMEM; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci buf[0] = 0x01; /* AV/C STATUS */ 598c2ecf20Sopenharmony_ci buf[1] = 0x08 | (0x07 & subunit_id); /* AUDIO SUBUNIT ID */ 608c2ecf20Sopenharmony_ci buf[2] = 0xb8; /* FUNCTION BLOCK */ 618c2ecf20Sopenharmony_ci buf[3] = 0x80; /* type is 'selector'*/ 628c2ecf20Sopenharmony_ci buf[4] = 0xff & fb_id; /* function block id */ 638c2ecf20Sopenharmony_ci buf[5] = 0x10; /* control attribute is CURRENT */ 648c2ecf20Sopenharmony_ci buf[6] = 0x02; /* selector length is 2 */ 658c2ecf20Sopenharmony_ci buf[7] = 0xff; /* input function block plug number */ 668c2ecf20Sopenharmony_ci buf[8] = 0x01; /* control selector is SELECTOR_CONTROL */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci err = fcp_avc_transaction(unit, buf, 12, buf, 12, 698c2ecf20Sopenharmony_ci BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 708c2ecf20Sopenharmony_ci BIT(6) | BIT(8)); 718c2ecf20Sopenharmony_ci if (err < 0) 728c2ecf20Sopenharmony_ci ; 738c2ecf20Sopenharmony_ci else if (err < 9) 748c2ecf20Sopenharmony_ci err = -EIO; 758c2ecf20Sopenharmony_ci else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 768c2ecf20Sopenharmony_ci err = -ENOSYS; 778c2ecf20Sopenharmony_ci else if (buf[0] == 0x0a) /* REJECTED */ 788c2ecf20Sopenharmony_ci err = -EINVAL; 798c2ecf20Sopenharmony_ci else if (buf[0] == 0x0b) /* IN TRANSITION */ 808c2ecf20Sopenharmony_ci err = -EAGAIN; 818c2ecf20Sopenharmony_ci if (err < 0) 828c2ecf20Sopenharmony_ci goto end; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci *num = buf[7]; 858c2ecf20Sopenharmony_ci err = 0; 868c2ecf20Sopenharmony_ciend: 878c2ecf20Sopenharmony_ci kfree(buf); 888c2ecf20Sopenharmony_ci return err; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic inline void 928c2ecf20Sopenharmony_ciavc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci buf[1] = addr[0]; 958c2ecf20Sopenharmony_ci memcpy(buf + 4, addr + 1, 5); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic inline void 998c2ecf20Sopenharmony_ciavc_bridgeco_fill_plug_info_extension_command(u8 *buf, u8 *addr, 1008c2ecf20Sopenharmony_ci unsigned int itype) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci buf[0] = 0x01; /* AV/C STATUS */ 1038c2ecf20Sopenharmony_ci buf[2] = 0x02; /* AV/C GENERAL PLUG INFO */ 1048c2ecf20Sopenharmony_ci buf[3] = 0xc0; /* BridgeCo extension */ 1058c2ecf20Sopenharmony_ci avc_bridgeco_fill_extension_addr(buf, addr); 1068c2ecf20Sopenharmony_ci buf[9] = itype; /* info type */ 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint avc_bridgeco_get_plug_type(struct fw_unit *unit, 1108c2ecf20Sopenharmony_ci u8 addr[AVC_BRIDGECO_ADDR_BYTES], 1118c2ecf20Sopenharmony_ci enum avc_bridgeco_plug_type *type) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci u8 *buf; 1148c2ecf20Sopenharmony_ci int err; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci buf = kzalloc(12, GFP_KERNEL); 1178c2ecf20Sopenharmony_ci if (buf == NULL) 1188c2ecf20Sopenharmony_ci return -ENOMEM; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Info type is 'plug type'. */ 1218c2ecf20Sopenharmony_ci avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x00); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci err = fcp_avc_transaction(unit, buf, 12, buf, 12, 1248c2ecf20Sopenharmony_ci BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 1258c2ecf20Sopenharmony_ci BIT(6) | BIT(7) | BIT(9)); 1268c2ecf20Sopenharmony_ci if (err < 0) 1278c2ecf20Sopenharmony_ci ; 1288c2ecf20Sopenharmony_ci else if (err < 11) 1298c2ecf20Sopenharmony_ci err = -EIO; 1308c2ecf20Sopenharmony_ci else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 1318c2ecf20Sopenharmony_ci err = -ENOSYS; 1328c2ecf20Sopenharmony_ci else if (buf[0] == 0x0a) /* REJECTED */ 1338c2ecf20Sopenharmony_ci err = -EINVAL; 1348c2ecf20Sopenharmony_ci else if (buf[0] == 0x0b) /* IN TRANSITION */ 1358c2ecf20Sopenharmony_ci err = -EAGAIN; 1368c2ecf20Sopenharmony_ci if (err < 0) 1378c2ecf20Sopenharmony_ci goto end; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci *type = buf[10]; 1408c2ecf20Sopenharmony_ci err = 0; 1418c2ecf20Sopenharmony_ciend: 1428c2ecf20Sopenharmony_ci kfree(buf); 1438c2ecf20Sopenharmony_ci return err; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciint avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, 1478c2ecf20Sopenharmony_ci u8 addr[AVC_BRIDGECO_ADDR_BYTES], 1488c2ecf20Sopenharmony_ci u8 *buf, unsigned int len) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int err; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* Info type is 'channel position'. */ 1538c2ecf20Sopenharmony_ci avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci err = fcp_avc_transaction(unit, buf, 12, buf, 256, 1568c2ecf20Sopenharmony_ci BIT(1) | BIT(2) | BIT(3) | BIT(4) | 1578c2ecf20Sopenharmony_ci BIT(5) | BIT(6) | BIT(7) | BIT(9)); 1588c2ecf20Sopenharmony_ci if (err < 0) 1598c2ecf20Sopenharmony_ci ; 1608c2ecf20Sopenharmony_ci else if (err < 11) 1618c2ecf20Sopenharmony_ci err = -EIO; 1628c2ecf20Sopenharmony_ci else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 1638c2ecf20Sopenharmony_ci err = -ENOSYS; 1648c2ecf20Sopenharmony_ci else if (buf[0] == 0x0a) /* REJECTED */ 1658c2ecf20Sopenharmony_ci err = -EINVAL; 1668c2ecf20Sopenharmony_ci else if (buf[0] == 0x0b) /* IN TRANSITION */ 1678c2ecf20Sopenharmony_ci err = -EAGAIN; 1688c2ecf20Sopenharmony_ci if (err < 0) 1698c2ecf20Sopenharmony_ci goto end; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Pick up specific data. */ 1728c2ecf20Sopenharmony_ci memmove(buf, buf + 10, err - 10); 1738c2ecf20Sopenharmony_ci err = 0; 1748c2ecf20Sopenharmony_ciend: 1758c2ecf20Sopenharmony_ci return err; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciint avc_bridgeco_get_plug_section_type(struct fw_unit *unit, 1798c2ecf20Sopenharmony_ci u8 addr[AVC_BRIDGECO_ADDR_BYTES], 1808c2ecf20Sopenharmony_ci unsigned int id, u8 *type) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci u8 *buf; 1838c2ecf20Sopenharmony_ci int err; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* section info includes charactors but this module don't need it */ 1868c2ecf20Sopenharmony_ci buf = kzalloc(12, GFP_KERNEL); 1878c2ecf20Sopenharmony_ci if (buf == NULL) 1888c2ecf20Sopenharmony_ci return -ENOMEM; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Info type is 'section info'. */ 1918c2ecf20Sopenharmony_ci avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07); 1928c2ecf20Sopenharmony_ci buf[10] = 0xff & ++id; /* section id */ 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci err = fcp_avc_transaction(unit, buf, 12, buf, 12, 1958c2ecf20Sopenharmony_ci BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 1968c2ecf20Sopenharmony_ci BIT(6) | BIT(7) | BIT(9) | BIT(10)); 1978c2ecf20Sopenharmony_ci if (err < 0) 1988c2ecf20Sopenharmony_ci ; 1998c2ecf20Sopenharmony_ci else if (err < 12) 2008c2ecf20Sopenharmony_ci err = -EIO; 2018c2ecf20Sopenharmony_ci else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 2028c2ecf20Sopenharmony_ci err = -ENOSYS; 2038c2ecf20Sopenharmony_ci else if (buf[0] == 0x0a) /* REJECTED */ 2048c2ecf20Sopenharmony_ci err = -EINVAL; 2058c2ecf20Sopenharmony_ci else if (buf[0] == 0x0b) /* IN TRANSITION */ 2068c2ecf20Sopenharmony_ci err = -EAGAIN; 2078c2ecf20Sopenharmony_ci if (err < 0) 2088c2ecf20Sopenharmony_ci goto end; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci *type = buf[11]; 2118c2ecf20Sopenharmony_ci err = 0; 2128c2ecf20Sopenharmony_ciend: 2138c2ecf20Sopenharmony_ci kfree(buf); 2148c2ecf20Sopenharmony_ci return err; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciint avc_bridgeco_get_plug_input(struct fw_unit *unit, 2188c2ecf20Sopenharmony_ci u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7]) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci int err; 2218c2ecf20Sopenharmony_ci u8 *buf; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci buf = kzalloc(18, GFP_KERNEL); 2248c2ecf20Sopenharmony_ci if (buf == NULL) 2258c2ecf20Sopenharmony_ci return -ENOMEM; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* Info type is 'plug input'. */ 2288c2ecf20Sopenharmony_ci avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci err = fcp_avc_transaction(unit, buf, 16, buf, 16, 2318c2ecf20Sopenharmony_ci BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 2328c2ecf20Sopenharmony_ci BIT(6) | BIT(7)); 2338c2ecf20Sopenharmony_ci if (err < 0) 2348c2ecf20Sopenharmony_ci ; 2358c2ecf20Sopenharmony_ci else if (err < 16) 2368c2ecf20Sopenharmony_ci err = -EIO; 2378c2ecf20Sopenharmony_ci else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 2388c2ecf20Sopenharmony_ci err = -ENOSYS; 2398c2ecf20Sopenharmony_ci else if (buf[0] == 0x0a) /* REJECTED */ 2408c2ecf20Sopenharmony_ci err = -EINVAL; 2418c2ecf20Sopenharmony_ci else if (buf[0] == 0x0b) /* IN TRANSITION */ 2428c2ecf20Sopenharmony_ci err = -EAGAIN; 2438c2ecf20Sopenharmony_ci if (err < 0) 2448c2ecf20Sopenharmony_ci goto end; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci memcpy(input, buf + 10, 5); 2478c2ecf20Sopenharmony_ci err = 0; 2488c2ecf20Sopenharmony_ciend: 2498c2ecf20Sopenharmony_ci kfree(buf); 2508c2ecf20Sopenharmony_ci return err; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ciint avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit, 2548c2ecf20Sopenharmony_ci u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf, 2558c2ecf20Sopenharmony_ci unsigned int *len, unsigned int eid) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci int err; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* check given buffer */ 2608c2ecf20Sopenharmony_ci if ((buf == NULL) || (*len < 12)) { 2618c2ecf20Sopenharmony_ci err = -EINVAL; 2628c2ecf20Sopenharmony_ci goto end; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci buf[0] = 0x01; /* AV/C STATUS */ 2668c2ecf20Sopenharmony_ci buf[2] = 0x2f; /* AV/C STREAM FORMAT SUPPORT */ 2678c2ecf20Sopenharmony_ci buf[3] = 0xc1; /* Bridgeco extension - List Request */ 2688c2ecf20Sopenharmony_ci avc_bridgeco_fill_extension_addr(buf, addr); 2698c2ecf20Sopenharmony_ci buf[10] = 0xff & eid; /* Entry ID */ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci err = fcp_avc_transaction(unit, buf, 12, buf, *len, 2728c2ecf20Sopenharmony_ci BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | 2738c2ecf20Sopenharmony_ci BIT(6) | BIT(7) | BIT(10)); 2748c2ecf20Sopenharmony_ci if (err < 0) 2758c2ecf20Sopenharmony_ci ; 2768c2ecf20Sopenharmony_ci else if (err < 12) 2778c2ecf20Sopenharmony_ci err = -EIO; 2788c2ecf20Sopenharmony_ci else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 2798c2ecf20Sopenharmony_ci err = -ENOSYS; 2808c2ecf20Sopenharmony_ci else if (buf[0] == 0x0a) /* REJECTED */ 2818c2ecf20Sopenharmony_ci err = -EINVAL; 2828c2ecf20Sopenharmony_ci else if (buf[0] == 0x0b) /* IN TRANSITION */ 2838c2ecf20Sopenharmony_ci err = -EAGAIN; 2848c2ecf20Sopenharmony_ci else if (buf[10] != eid) 2858c2ecf20Sopenharmony_ci err = -EIO; 2868c2ecf20Sopenharmony_ci if (err < 0) 2878c2ecf20Sopenharmony_ci goto end; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Pick up 'stream format info'. */ 2908c2ecf20Sopenharmony_ci memmove(buf, buf + 11, err - 11); 2918c2ecf20Sopenharmony_ci *len = err - 11; 2928c2ecf20Sopenharmony_ci err = 0; 2938c2ecf20Sopenharmony_ciend: 2948c2ecf20Sopenharmony_ci return err; 2958c2ecf20Sopenharmony_ci} 296