18c2ecf20Sopenharmony_ci/**************************************************************************** 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci Copyright Echo Digital Audio Corporation (c) 1998 - 2004 48c2ecf20Sopenharmony_ci All rights reserved 58c2ecf20Sopenharmony_ci www.echoaudio.com 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci This file is part of Echo Digital Audio's generic driver library. 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci Echo Digital Audio's generic driver library is free software; 108c2ecf20Sopenharmony_ci you can redistribute it and/or modify it under the terms of 118c2ecf20Sopenharmony_ci the GNU General Public License as published by the Free Software 128c2ecf20Sopenharmony_ci Foundation. 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci This program is distributed in the hope that it will be useful, 158c2ecf20Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178c2ecf20Sopenharmony_ci GNU General Public License for more details. 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci You should have received a copy of the GNU General Public License 208c2ecf20Sopenharmony_ci along with this program; if not, write to the Free Software 218c2ecf20Sopenharmony_ci Foundation, Inc., 59 Temple Place - Suite 330, Boston, 228c2ecf20Sopenharmony_ci MA 02111-1307, USA. 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci ************************************************************************* 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci Translation from C++ and adaptation for use in ALSA-Driver 278c2ecf20Sopenharmony_ci were made by Giuliano Pochini <pochini@shiny.it> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci****************************************************************************/ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#if PAGE_SIZE < 4096 328c2ecf20Sopenharmony_ci#error PAGE_SIZE is < 4k 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int restore_dsp_rettings(struct echoaudio *chip); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Some vector commands involve the DSP reading or writing data to and from the 398c2ecf20Sopenharmony_cicomm page; if you send one of these commands to the DSP, it will complete the 408c2ecf20Sopenharmony_cicommand and then write a non-zero value to the Handshake field in the 418c2ecf20Sopenharmony_cicomm page. This function waits for the handshake to show up. */ 428c2ecf20Sopenharmony_cistatic int wait_handshake(struct echoaudio *chip) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int i; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* Wait up to 20ms for the handshake from the DSP */ 478c2ecf20Sopenharmony_ci for (i = 0; i < HANDSHAKE_TIMEOUT; i++) { 488c2ecf20Sopenharmony_ci /* Look for the handshake value */ 498c2ecf20Sopenharmony_ci barrier(); 508c2ecf20Sopenharmony_ci if (chip->comm_page->handshake) { 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci udelay(1); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "wait_handshake(): Timeout waiting for DSP\n"); 578c2ecf20Sopenharmony_ci return -EBUSY; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Much of the interaction between the DSP and the driver is done via vector 638c2ecf20Sopenharmony_cicommands; send_vector writes a vector command to the DSP. Typically, this 648c2ecf20Sopenharmony_cicauses the DSP to read or write fields in the comm page. 658c2ecf20Sopenharmony_ciPCI posting is not required thanks to the handshake logic. */ 668c2ecf20Sopenharmony_cistatic int send_vector(struct echoaudio *chip, u32 command) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int i; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci wmb(); /* Flush all pending writes before sending the command */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Wait up to 100ms for the "vector busy" bit to be off */ 738c2ecf20Sopenharmony_ci for (i = 0; i < VECTOR_BUSY_TIMEOUT; i++) { 748c2ecf20Sopenharmony_ci if (!(get_dsp_register(chip, CHI32_VECTOR_REG) & 758c2ecf20Sopenharmony_ci CHI32_VECTOR_BUSY)) { 768c2ecf20Sopenharmony_ci set_dsp_register(chip, CHI32_VECTOR_REG, command); 778c2ecf20Sopenharmony_ci /*if (i) DE_ACT(("send_vector time: %d\n", i));*/ 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci udelay(1); 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "timeout on send_vector\n"); 848c2ecf20Sopenharmony_ci return -EBUSY; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* write_dsp writes a 32-bit value to the DSP; this is used almost 908c2ecf20Sopenharmony_ciexclusively for loading the DSP. */ 918c2ecf20Sopenharmony_cistatic int write_dsp(struct echoaudio *chip, u32 data) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci u32 status, i; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci for (i = 0; i < 10000000; i++) { /* timeout = 10s */ 968c2ecf20Sopenharmony_ci status = get_dsp_register(chip, CHI32_STATUS_REG); 978c2ecf20Sopenharmony_ci if ((status & CHI32_STATUS_HOST_WRITE_EMPTY) != 0) { 988c2ecf20Sopenharmony_ci set_dsp_register(chip, CHI32_DATA_REG, data); 998c2ecf20Sopenharmony_ci wmb(); /* write it immediately */ 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci udelay(1); 1038c2ecf20Sopenharmony_ci cond_resched(); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci chip->bad_board = true; /* Set true until DSP re-loaded */ 1078c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "write_dsp: Set bad_board to true\n"); 1088c2ecf20Sopenharmony_ci return -EIO; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* read_dsp reads a 32-bit value from the DSP; this is used almost 1148c2ecf20Sopenharmony_ciexclusively for loading the DSP and checking the status of the ASIC. */ 1158c2ecf20Sopenharmony_cistatic int read_dsp(struct echoaudio *chip, u32 *data) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci u32 status, i; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci for (i = 0; i < READ_DSP_TIMEOUT; i++) { 1208c2ecf20Sopenharmony_ci status = get_dsp_register(chip, CHI32_STATUS_REG); 1218c2ecf20Sopenharmony_ci if ((status & CHI32_STATUS_HOST_READ_FULL) != 0) { 1228c2ecf20Sopenharmony_ci *data = get_dsp_register(chip, CHI32_DATA_REG); 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci udelay(1); 1268c2ecf20Sopenharmony_ci cond_resched(); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci chip->bad_board = true; /* Set true until DSP re-loaded */ 1308c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "read_dsp: Set bad_board to true\n"); 1318c2ecf20Sopenharmony_ci return -EIO; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/**************************************************************************** 1378c2ecf20Sopenharmony_ci Firmware loading functions 1388c2ecf20Sopenharmony_ci ****************************************************************************/ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* This function is used to read back the serial number from the DSP; 1418c2ecf20Sopenharmony_cithis is triggered by the SET_COMMPAGE_ADDR command. 1428c2ecf20Sopenharmony_ciOnly some early Echogals products have serial numbers in the ROM; 1438c2ecf20Sopenharmony_cithe serial number is not used, but you still need to do this as 1448c2ecf20Sopenharmony_cipart of the DSP load process. */ 1458c2ecf20Sopenharmony_cistatic int read_sn(struct echoaudio *chip) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int i; 1488c2ecf20Sopenharmony_ci u32 sn[6]; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 1518c2ecf20Sopenharmony_ci if (read_dsp(chip, &sn[i])) { 1528c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 1538c2ecf20Sopenharmony_ci "Failed to read serial number\n"); 1548c2ecf20Sopenharmony_ci return -EIO; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 1588c2ecf20Sopenharmony_ci "Read serial number %08x %08x %08x %08x %08x\n", 1598c2ecf20Sopenharmony_ci sn[0], sn[1], sn[2], sn[3], sn[4]); 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#ifndef ECHOCARD_HAS_ASIC 1668c2ecf20Sopenharmony_ci/* This card has no ASIC, just return ok */ 1678c2ecf20Sopenharmony_cistatic inline int check_asic_status(struct echoaudio *chip) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci chip->asic_loaded = true; 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#endif /* !ECHOCARD_HAS_ASIC */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_ASIC 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* Load ASIC code - done after the DSP is loaded */ 1808c2ecf20Sopenharmony_cistatic int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci const struct firmware *fw; 1838c2ecf20Sopenharmony_ci int err; 1848c2ecf20Sopenharmony_ci u32 i, size; 1858c2ecf20Sopenharmony_ci u8 *code; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci err = get_firmware(&fw, chip, asic); 1888c2ecf20Sopenharmony_ci if (err < 0) { 1898c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, "Firmware not found !\n"); 1908c2ecf20Sopenharmony_ci return err; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci code = (u8 *)fw->data; 1948c2ecf20Sopenharmony_ci size = fw->size; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Send the "Here comes the ASIC" command */ 1978c2ecf20Sopenharmony_ci if (write_dsp(chip, cmd) < 0) 1988c2ecf20Sopenharmony_ci goto la_error; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* Write length of ASIC file in bytes */ 2018c2ecf20Sopenharmony_ci if (write_dsp(chip, size) < 0) 2028c2ecf20Sopenharmony_ci goto la_error; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 2058c2ecf20Sopenharmony_ci if (write_dsp(chip, code[i]) < 0) 2068c2ecf20Sopenharmony_ci goto la_error; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci free_firmware(fw, chip); 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cila_error: 2138c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "failed on write_dsp\n"); 2148c2ecf20Sopenharmony_ci free_firmware(fw, chip); 2158c2ecf20Sopenharmony_ci return -EIO; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci#endif /* ECHOCARD_HAS_ASIC */ 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#ifdef DSP_56361 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* Install the resident loader for 56361 DSPs; The resident loader is on 2258c2ecf20Sopenharmony_cithe EPROM on the board for 56301 DSP. The resident loader is a tiny little 2268c2ecf20Sopenharmony_ciprogram that is used to load the real DSP code. */ 2278c2ecf20Sopenharmony_cistatic int install_resident_loader(struct echoaudio *chip) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci u32 address; 2308c2ecf20Sopenharmony_ci int index, words, i; 2318c2ecf20Sopenharmony_ci u16 *code; 2328c2ecf20Sopenharmony_ci u32 status; 2338c2ecf20Sopenharmony_ci const struct firmware *fw; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* 56361 cards only! This check is required by the old 56301-based 2368c2ecf20Sopenharmony_ci Mona and Gina24 */ 2378c2ecf20Sopenharmony_ci if (chip->device_id != DEVICE_ID_56361) 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Look to see if the resident loader is present. If the resident 2418c2ecf20Sopenharmony_ci loader is already installed, host flag 5 will be on. */ 2428c2ecf20Sopenharmony_ci status = get_dsp_register(chip, CHI32_STATUS_REG); 2438c2ecf20Sopenharmony_ci if (status & CHI32_STATUS_REG_HF5) { 2448c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 2458c2ecf20Sopenharmony_ci "Resident loader already installed; status is 0x%x\n", 2468c2ecf20Sopenharmony_ci status); 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci i = get_firmware(&fw, chip, FW_361_LOADER); 2518c2ecf20Sopenharmony_ci if (i < 0) { 2528c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, "Firmware not found !\n"); 2538c2ecf20Sopenharmony_ci return i; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* The DSP code is an array of 16 bit words. The array is divided up 2578c2ecf20Sopenharmony_ci into sections. The first word of each section is the size in words, 2588c2ecf20Sopenharmony_ci followed by the section type. 2598c2ecf20Sopenharmony_ci Since DSP addresses and data are 24 bits wide, they each take up two 2608c2ecf20Sopenharmony_ci 16 bit words in the array. 2618c2ecf20Sopenharmony_ci This is a lot like the other loader loop, but it's not a loop, you 2628c2ecf20Sopenharmony_ci don't write the memory type, and you don't write a zero at the end. */ 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Set DSP format bits for 24 bit mode */ 2658c2ecf20Sopenharmony_ci set_dsp_register(chip, CHI32_CONTROL_REG, 2668c2ecf20Sopenharmony_ci get_dsp_register(chip, CHI32_CONTROL_REG) | 0x900); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci code = (u16 *)fw->data; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Skip the header section; the first word in the array is the size 2718c2ecf20Sopenharmony_ci of the first section, so the first real section of code is pointed 2728c2ecf20Sopenharmony_ci to by Code[0]. */ 2738c2ecf20Sopenharmony_ci index = code[0]; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Skip the section size, LRS block type, and DSP memory type */ 2768c2ecf20Sopenharmony_ci index += 3; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Get the number of DSP words to write */ 2798c2ecf20Sopenharmony_ci words = code[index++]; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Get the DSP address for this block; 24 bits, so build from two words */ 2828c2ecf20Sopenharmony_ci address = ((u32)code[index] << 16) + code[index + 1]; 2838c2ecf20Sopenharmony_ci index += 2; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Write the count to the DSP */ 2868c2ecf20Sopenharmony_ci if (write_dsp(chip, words)) { 2878c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 2888c2ecf20Sopenharmony_ci "install_resident_loader: Failed to write word count!\n"); 2898c2ecf20Sopenharmony_ci goto irl_error; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci /* Write the DSP address */ 2928c2ecf20Sopenharmony_ci if (write_dsp(chip, address)) { 2938c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 2948c2ecf20Sopenharmony_ci "install_resident_loader: Failed to write DSP address!\n"); 2958c2ecf20Sopenharmony_ci goto irl_error; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci /* Write out this block of code to the DSP */ 2988c2ecf20Sopenharmony_ci for (i = 0; i < words; i++) { 2998c2ecf20Sopenharmony_ci u32 data; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci data = ((u32)code[index] << 16) + code[index + 1]; 3028c2ecf20Sopenharmony_ci if (write_dsp(chip, data)) { 3038c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 3048c2ecf20Sopenharmony_ci "install_resident_loader: Failed to write DSP code\n"); 3058c2ecf20Sopenharmony_ci goto irl_error; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci index += 2; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Wait for flag 5 to come up */ 3118c2ecf20Sopenharmony_ci for (i = 0; i < 200; i++) { /* Timeout is 50us * 200 = 10ms */ 3128c2ecf20Sopenharmony_ci udelay(50); 3138c2ecf20Sopenharmony_ci status = get_dsp_register(chip, CHI32_STATUS_REG); 3148c2ecf20Sopenharmony_ci if (status & CHI32_STATUS_REG_HF5) 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (i == 200) { 3198c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "Resident loader failed to set HF5\n"); 3208c2ecf20Sopenharmony_ci goto irl_error; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "Resident loader successfully installed\n"); 3248c2ecf20Sopenharmony_ci free_firmware(fw, chip); 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ciirl_error: 3288c2ecf20Sopenharmony_ci free_firmware(fw, chip); 3298c2ecf20Sopenharmony_ci return -EIO; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci#endif /* DSP_56361 */ 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int load_dsp(struct echoaudio *chip, u16 *code) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci u32 address, data; 3388c2ecf20Sopenharmony_ci int index, words, i; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (chip->dsp_code == code) { 3418c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, "DSP is already loaded!\n"); 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci chip->bad_board = true; /* Set true until DSP loaded */ 3458c2ecf20Sopenharmony_ci chip->dsp_code = NULL; /* Current DSP code not loaded */ 3468c2ecf20Sopenharmony_ci chip->asic_loaded = false; /* Loading the DSP code will reset the ASIC */ 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "load_dsp: Set bad_board to true\n"); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* If this board requires a resident loader, install it. */ 3518c2ecf20Sopenharmony_ci#ifdef DSP_56361 3528c2ecf20Sopenharmony_ci if ((i = install_resident_loader(chip)) < 0) 3538c2ecf20Sopenharmony_ci return i; 3548c2ecf20Sopenharmony_ci#endif 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Send software reset command */ 3578c2ecf20Sopenharmony_ci if (send_vector(chip, DSP_VC_RESET) < 0) { 3588c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 3598c2ecf20Sopenharmony_ci "LoadDsp: send_vector DSP_VC_RESET failed, Critical Failure\n"); 3608c2ecf20Sopenharmony_ci return -EIO; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci /* Delay 10us */ 3638c2ecf20Sopenharmony_ci udelay(10); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* Wait 10ms for HF3 to indicate that software reset is complete */ 3668c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { /* Timeout is 10us * 1000 = 10ms */ 3678c2ecf20Sopenharmony_ci if (get_dsp_register(chip, CHI32_STATUS_REG) & 3688c2ecf20Sopenharmony_ci CHI32_STATUS_REG_HF3) 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci udelay(10); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (i == 1000) { 3748c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 3758c2ecf20Sopenharmony_ci "load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n"); 3768c2ecf20Sopenharmony_ci return -EIO; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Set DSP format bits for 24 bit mode now that soft reset is done */ 3808c2ecf20Sopenharmony_ci set_dsp_register(chip, CHI32_CONTROL_REG, 3818c2ecf20Sopenharmony_ci get_dsp_register(chip, CHI32_CONTROL_REG) | 0x900); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Main loader loop */ 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci index = code[0]; 3868c2ecf20Sopenharmony_ci for (;;) { 3878c2ecf20Sopenharmony_ci int block_type, mem_type; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Total Block Size */ 3908c2ecf20Sopenharmony_ci index++; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* Block Type */ 3938c2ecf20Sopenharmony_ci block_type = code[index]; 3948c2ecf20Sopenharmony_ci if (block_type == 4) /* We're finished */ 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci index++; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Memory Type P=0,X=1,Y=2 */ 4008c2ecf20Sopenharmony_ci mem_type = code[index++]; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* Block Code Size */ 4038c2ecf20Sopenharmony_ci words = code[index++]; 4048c2ecf20Sopenharmony_ci if (words == 0) /* We're finished */ 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Start Address */ 4088c2ecf20Sopenharmony_ci address = ((u32)code[index] << 16) + code[index + 1]; 4098c2ecf20Sopenharmony_ci index += 2; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (write_dsp(chip, words) < 0) { 4128c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4138c2ecf20Sopenharmony_ci "load_dsp: failed to write number of DSP words\n"); 4148c2ecf20Sopenharmony_ci return -EIO; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci if (write_dsp(chip, address) < 0) { 4178c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4188c2ecf20Sopenharmony_ci "load_dsp: failed to write DSP address\n"); 4198c2ecf20Sopenharmony_ci return -EIO; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci if (write_dsp(chip, mem_type) < 0) { 4228c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4238c2ecf20Sopenharmony_ci "load_dsp: failed to write DSP memory type\n"); 4248c2ecf20Sopenharmony_ci return -EIO; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci /* Code */ 4278c2ecf20Sopenharmony_ci for (i = 0; i < words; i++, index+=2) { 4288c2ecf20Sopenharmony_ci data = ((u32)code[index] << 16) + code[index + 1]; 4298c2ecf20Sopenharmony_ci if (write_dsp(chip, data) < 0) { 4308c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4318c2ecf20Sopenharmony_ci "load_dsp: failed to write DSP data\n"); 4328c2ecf20Sopenharmony_ci return -EIO; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (write_dsp(chip, 0) < 0) { /* We're done!!! */ 4388c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4398c2ecf20Sopenharmony_ci "load_dsp: Failed to write final zero\n"); 4408c2ecf20Sopenharmony_ci return -EIO; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci udelay(10); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci for (i = 0; i < 5000; i++) { /* Timeout is 100us * 5000 = 500ms */ 4458c2ecf20Sopenharmony_ci /* Wait for flag 4 - indicates that the DSP loaded OK */ 4468c2ecf20Sopenharmony_ci if (get_dsp_register(chip, CHI32_STATUS_REG) & 4478c2ecf20Sopenharmony_ci CHI32_STATUS_REG_HF4) { 4488c2ecf20Sopenharmony_ci set_dsp_register(chip, CHI32_CONTROL_REG, 4498c2ecf20Sopenharmony_ci get_dsp_register(chip, CHI32_CONTROL_REG) & ~0x1b00); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (write_dsp(chip, DSP_FNC_SET_COMMPAGE_ADDR) < 0) { 4528c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4538c2ecf20Sopenharmony_ci "load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n"); 4548c2ecf20Sopenharmony_ci return -EIO; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (write_dsp(chip, chip->comm_page_phys) < 0) { 4588c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4598c2ecf20Sopenharmony_ci "load_dsp: Failed to write comm page address\n"); 4608c2ecf20Sopenharmony_ci return -EIO; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* Get the serial number via slave mode. 4648c2ecf20Sopenharmony_ci This is triggered by the SET_COMMPAGE_ADDR command. 4658c2ecf20Sopenharmony_ci We don't actually use the serial number but we have to 4668c2ecf20Sopenharmony_ci get it as part of the DSP init voodoo. */ 4678c2ecf20Sopenharmony_ci if (read_sn(chip) < 0) { 4688c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4698c2ecf20Sopenharmony_ci "load_dsp: Failed to read serial number\n"); 4708c2ecf20Sopenharmony_ci return -EIO; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci chip->dsp_code = code; /* Show which DSP code loaded */ 4748c2ecf20Sopenharmony_ci chip->bad_board = false; /* DSP OK */ 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci udelay(100); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 4818c2ecf20Sopenharmony_ci "load_dsp: DSP load timed out waiting for HF4\n"); 4828c2ecf20Sopenharmony_ci return -EIO; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci/* load_firmware takes care of loading the DSP and any ASIC code. */ 4888c2ecf20Sopenharmony_cistatic int load_firmware(struct echoaudio *chip) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci const struct firmware *fw; 4918c2ecf20Sopenharmony_ci int box_type, err; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (snd_BUG_ON(!chip->comm_page)) 4948c2ecf20Sopenharmony_ci return -EPERM; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* See if the ASIC is present and working - only if the DSP is already loaded */ 4978c2ecf20Sopenharmony_ci if (chip->dsp_code) { 4988c2ecf20Sopenharmony_ci if ((box_type = check_asic_status(chip)) >= 0) 4998c2ecf20Sopenharmony_ci return box_type; 5008c2ecf20Sopenharmony_ci /* ASIC check failed; force the DSP to reload */ 5018c2ecf20Sopenharmony_ci chip->dsp_code = NULL; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci err = get_firmware(&fw, chip, chip->dsp_code_to_load); 5058c2ecf20Sopenharmony_ci if (err < 0) 5068c2ecf20Sopenharmony_ci return err; 5078c2ecf20Sopenharmony_ci err = load_dsp(chip, (u16 *)fw->data); 5088c2ecf20Sopenharmony_ci free_firmware(fw, chip); 5098c2ecf20Sopenharmony_ci if (err < 0) 5108c2ecf20Sopenharmony_ci return err; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if ((box_type = load_asic(chip)) < 0) 5138c2ecf20Sopenharmony_ci return box_type; /* error */ 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci return box_type; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/**************************************************************************** 5218c2ecf20Sopenharmony_ci Mixer functions 5228c2ecf20Sopenharmony_ci ****************************************************************************/ 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci#if defined(ECHOCARD_HAS_INPUT_NOMINAL_LEVEL) || \ 5258c2ecf20Sopenharmony_ci defined(ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL) 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/* Set the nominal level for an input or output bus (true = -10dBV, false = +4dBu) */ 5288c2ecf20Sopenharmony_cistatic int set_nominal_level(struct echoaudio *chip, u16 index, char consumer) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci if (snd_BUG_ON(index >= num_busses_out(chip) + num_busses_in(chip))) 5318c2ecf20Sopenharmony_ci return -EINVAL; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* Wait for the handshake (OK even if ASIC is not loaded) */ 5348c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 5358c2ecf20Sopenharmony_ci return -EIO; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci chip->nominal_level[index] = consumer; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (consumer) 5408c2ecf20Sopenharmony_ci chip->comm_page->nominal_level_mask |= cpu_to_le32(1 << index); 5418c2ecf20Sopenharmony_ci else 5428c2ecf20Sopenharmony_ci chip->comm_page->nominal_level_mask &= ~cpu_to_le32(1 << index); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci#endif /* ECHOCARD_HAS_*_NOMINAL_LEVEL */ 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/* Set the gain for a single physical output channel (dB). */ 5528c2ecf20Sopenharmony_cistatic int set_output_gain(struct echoaudio *chip, u16 channel, s8 gain) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci if (snd_BUG_ON(channel >= num_busses_out(chip))) 5558c2ecf20Sopenharmony_ci return -EINVAL; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 5588c2ecf20Sopenharmony_ci return -EIO; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* Save the new value */ 5618c2ecf20Sopenharmony_ci chip->output_gain[channel] = gain; 5628c2ecf20Sopenharmony_ci chip->comm_page->line_out_level[channel] = gain; 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_MONITOR 5698c2ecf20Sopenharmony_ci/* Set the monitor level from an input bus to an output bus. */ 5708c2ecf20Sopenharmony_cistatic int set_monitor_gain(struct echoaudio *chip, u16 output, u16 input, 5718c2ecf20Sopenharmony_ci s8 gain) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci if (snd_BUG_ON(output >= num_busses_out(chip) || 5748c2ecf20Sopenharmony_ci input >= num_busses_in(chip))) 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 5788c2ecf20Sopenharmony_ci return -EIO; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci chip->monitor_gain[output][input] = gain; 5818c2ecf20Sopenharmony_ci chip->comm_page->monitors[monitor_index(chip, output, input)] = gain; 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci#endif /* ECHOCARD_HAS_MONITOR */ 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* Tell the DSP to read and update output, nominal & monitor levels in comm page. */ 5888c2ecf20Sopenharmony_cistatic int update_output_line_level(struct echoaudio *chip) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 5918c2ecf20Sopenharmony_ci return -EIO; 5928c2ecf20Sopenharmony_ci clear_handshake(chip); 5938c2ecf20Sopenharmony_ci return send_vector(chip, DSP_VC_UPDATE_OUTVOL); 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/* Tell the DSP to read and update input levels in comm page */ 5998c2ecf20Sopenharmony_cistatic int update_input_line_level(struct echoaudio *chip) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 6028c2ecf20Sopenharmony_ci return -EIO; 6038c2ecf20Sopenharmony_ci clear_handshake(chip); 6048c2ecf20Sopenharmony_ci return send_vector(chip, DSP_VC_UPDATE_INGAIN); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/* set_meters_on turns the meters on or off. If meters are turned on, the DSP 6108c2ecf20Sopenharmony_ciwill write the meter and clock detect values to the comm page at about 30Hz */ 6118c2ecf20Sopenharmony_cistatic void set_meters_on(struct echoaudio *chip, char on) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci if (on && !chip->meters_enabled) { 6148c2ecf20Sopenharmony_ci send_vector(chip, DSP_VC_METERS_ON); 6158c2ecf20Sopenharmony_ci chip->meters_enabled = 1; 6168c2ecf20Sopenharmony_ci } else if (!on && chip->meters_enabled) { 6178c2ecf20Sopenharmony_ci send_vector(chip, DSP_VC_METERS_OFF); 6188c2ecf20Sopenharmony_ci chip->meters_enabled = 0; 6198c2ecf20Sopenharmony_ci memset((s8 *)chip->comm_page->vu_meter, ECHOGAIN_MUTED, 6208c2ecf20Sopenharmony_ci DSP_MAXPIPES); 6218c2ecf20Sopenharmony_ci memset((s8 *)chip->comm_page->peak_meter, ECHOGAIN_MUTED, 6228c2ecf20Sopenharmony_ci DSP_MAXPIPES); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci/* Fill out an the given array using the current values in the comm page. 6298c2ecf20Sopenharmony_ciMeters are written in the comm page by the DSP in this order: 6308c2ecf20Sopenharmony_ci Output busses 6318c2ecf20Sopenharmony_ci Input busses 6328c2ecf20Sopenharmony_ci Output pipes (vmixer cards only) 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ciThis function assumes there are no more than 16 in/out busses or pipes 6358c2ecf20Sopenharmony_ciMeters is an array [3][16][2] of long. */ 6368c2ecf20Sopenharmony_cistatic void get_audio_meters(struct echoaudio *chip, long *meters) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci unsigned int i, m, n; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci for (i = 0 ; i < 96; i++) 6418c2ecf20Sopenharmony_ci meters[i] = 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci for (m = 0, n = 0, i = 0; i < num_busses_out(chip); i++, m++) { 6448c2ecf20Sopenharmony_ci meters[n++] = chip->comm_page->vu_meter[m]; 6458c2ecf20Sopenharmony_ci meters[n++] = chip->comm_page->peak_meter[m]; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci#ifdef ECHOCARD_ECHO3G 6498c2ecf20Sopenharmony_ci m = E3G_MAX_OUTPUTS; /* Skip unused meters */ 6508c2ecf20Sopenharmony_ci#endif 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci for (n = 32, i = 0; i < num_busses_in(chip); i++, m++) { 6538c2ecf20Sopenharmony_ci meters[n++] = chip->comm_page->vu_meter[m]; 6548c2ecf20Sopenharmony_ci meters[n++] = chip->comm_page->peak_meter[m]; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_VMIXER 6578c2ecf20Sopenharmony_ci for (n = 64, i = 0; i < num_pipes_out(chip); i++, m++) { 6588c2ecf20Sopenharmony_ci meters[n++] = chip->comm_page->vu_meter[m]; 6598c2ecf20Sopenharmony_ci meters[n++] = chip->comm_page->peak_meter[m]; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci#endif 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic int restore_dsp_rettings(struct echoaudio *chip) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci int i, o, err; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if ((err = check_asic_status(chip)) < 0) 6718c2ecf20Sopenharmony_ci return err; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* Gina20/Darla20 only. Should be harmless for other cards. */ 6748c2ecf20Sopenharmony_ci chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF; 6758c2ecf20Sopenharmony_ci chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF; 6768c2ecf20Sopenharmony_ci chip->comm_page->handshake = cpu_to_le32(0xffffffff); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* Restore output busses */ 6798c2ecf20Sopenharmony_ci for (i = 0; i < num_busses_out(chip); i++) { 6808c2ecf20Sopenharmony_ci err = set_output_gain(chip, i, chip->output_gain[i]); 6818c2ecf20Sopenharmony_ci if (err < 0) 6828c2ecf20Sopenharmony_ci return err; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_VMIXER 6868c2ecf20Sopenharmony_ci for (i = 0; i < num_pipes_out(chip); i++) 6878c2ecf20Sopenharmony_ci for (o = 0; o < num_busses_out(chip); o++) { 6888c2ecf20Sopenharmony_ci err = set_vmixer_gain(chip, o, i, 6898c2ecf20Sopenharmony_ci chip->vmixer_gain[o][i]); 6908c2ecf20Sopenharmony_ci if (err < 0) 6918c2ecf20Sopenharmony_ci return err; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci if (update_vmixer_level(chip) < 0) 6948c2ecf20Sopenharmony_ci return -EIO; 6958c2ecf20Sopenharmony_ci#endif /* ECHOCARD_HAS_VMIXER */ 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_MONITOR 6988c2ecf20Sopenharmony_ci for (o = 0; o < num_busses_out(chip); o++) 6998c2ecf20Sopenharmony_ci for (i = 0; i < num_busses_in(chip); i++) { 7008c2ecf20Sopenharmony_ci err = set_monitor_gain(chip, o, i, 7018c2ecf20Sopenharmony_ci chip->monitor_gain[o][i]); 7028c2ecf20Sopenharmony_ci if (err < 0) 7038c2ecf20Sopenharmony_ci return err; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci#endif /* ECHOCARD_HAS_MONITOR */ 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_INPUT_GAIN 7088c2ecf20Sopenharmony_ci for (i = 0; i < num_busses_in(chip); i++) { 7098c2ecf20Sopenharmony_ci err = set_input_gain(chip, i, chip->input_gain[i]); 7108c2ecf20Sopenharmony_ci if (err < 0) 7118c2ecf20Sopenharmony_ci return err; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci#endif /* ECHOCARD_HAS_INPUT_GAIN */ 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci err = update_output_line_level(chip); 7168c2ecf20Sopenharmony_ci if (err < 0) 7178c2ecf20Sopenharmony_ci return err; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci err = update_input_line_level(chip); 7208c2ecf20Sopenharmony_ci if (err < 0) 7218c2ecf20Sopenharmony_ci return err; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci err = set_sample_rate(chip, chip->sample_rate); 7248c2ecf20Sopenharmony_ci if (err < 0) 7258c2ecf20Sopenharmony_ci return err; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (chip->meters_enabled) { 7288c2ecf20Sopenharmony_ci err = send_vector(chip, DSP_VC_METERS_ON); 7298c2ecf20Sopenharmony_ci if (err < 0) 7308c2ecf20Sopenharmony_ci return err; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH 7348c2ecf20Sopenharmony_ci if (set_digital_mode(chip, chip->digital_mode) < 0) 7358c2ecf20Sopenharmony_ci return -EIO; 7368c2ecf20Sopenharmony_ci#endif 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IO 7398c2ecf20Sopenharmony_ci if (set_professional_spdif(chip, chip->professional_spdif) < 0) 7408c2ecf20Sopenharmony_ci return -EIO; 7418c2ecf20Sopenharmony_ci#endif 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_PHANTOM_POWER 7448c2ecf20Sopenharmony_ci if (set_phantom_power(chip, chip->phantom_power) < 0) 7458c2ecf20Sopenharmony_ci return -EIO; 7468c2ecf20Sopenharmony_ci#endif 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK 7498c2ecf20Sopenharmony_ci /* set_input_clock() also restores automute setting */ 7508c2ecf20Sopenharmony_ci if (set_input_clock(chip, chip->input_clock) < 0) 7518c2ecf20Sopenharmony_ci return -EIO; 7528c2ecf20Sopenharmony_ci#endif 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH 7558c2ecf20Sopenharmony_ci if (set_output_clock(chip, chip->output_clock) < 0) 7568c2ecf20Sopenharmony_ci return -EIO; 7578c2ecf20Sopenharmony_ci#endif 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (wait_handshake(chip) < 0) 7608c2ecf20Sopenharmony_ci return -EIO; 7618c2ecf20Sopenharmony_ci clear_handshake(chip); 7628c2ecf20Sopenharmony_ci if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0) 7638c2ecf20Sopenharmony_ci return -EIO; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return 0; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci/**************************************************************************** 7718c2ecf20Sopenharmony_ci Transport functions 7728c2ecf20Sopenharmony_ci ****************************************************************************/ 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/* set_audio_format() sets the format of the audio data in host memory for 7758c2ecf20Sopenharmony_cithis pipe. Note that _MS_ (mono-to-stereo) playback modes are not used by ALSA 7768c2ecf20Sopenharmony_cibut they are here because they are just mono while capturing */ 7778c2ecf20Sopenharmony_cistatic void set_audio_format(struct echoaudio *chip, u16 pipe_index, 7788c2ecf20Sopenharmony_ci const struct audioformat *format) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci u16 dsp_format; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SS_16LE; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* Look for super-interleave (no big-endian and 8 bits) */ 7858c2ecf20Sopenharmony_ci if (format->interleave > 2) { 7868c2ecf20Sopenharmony_ci switch (format->bits_per_sample) { 7878c2ecf20Sopenharmony_ci case 16: 7888c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_16LE; 7898c2ecf20Sopenharmony_ci break; 7908c2ecf20Sopenharmony_ci case 24: 7918c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_24LE; 7928c2ecf20Sopenharmony_ci break; 7938c2ecf20Sopenharmony_ci case 32: 7948c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_32LE; 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci dsp_format |= format->interleave; 7988c2ecf20Sopenharmony_ci } else if (format->data_are_bigendian) { 7998c2ecf20Sopenharmony_ci /* For big-endian data, only 32 bit samples are supported */ 8008c2ecf20Sopenharmony_ci switch (format->interleave) { 8018c2ecf20Sopenharmony_ci case 1: 8028c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_MM_32BE; 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 8058c2ecf20Sopenharmony_ci case 2: 8068c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SS_32BE; 8078c2ecf20Sopenharmony_ci break; 8088c2ecf20Sopenharmony_ci#endif 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci } else if (format->interleave == 1 && 8118c2ecf20Sopenharmony_ci format->bits_per_sample == 32 && !format->mono_to_stereo) { 8128c2ecf20Sopenharmony_ci /* 32 bit little-endian mono->mono case */ 8138c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_MM_32LE; 8148c2ecf20Sopenharmony_ci } else { 8158c2ecf20Sopenharmony_ci /* Handle the other little-endian formats */ 8168c2ecf20Sopenharmony_ci switch (format->bits_per_sample) { 8178c2ecf20Sopenharmony_ci case 8: 8188c2ecf20Sopenharmony_ci if (format->interleave == 2) 8198c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SS_8; 8208c2ecf20Sopenharmony_ci else 8218c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_MS_8; 8228c2ecf20Sopenharmony_ci break; 8238c2ecf20Sopenharmony_ci default: 8248c2ecf20Sopenharmony_ci case 16: 8258c2ecf20Sopenharmony_ci if (format->interleave == 2) 8268c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SS_16LE; 8278c2ecf20Sopenharmony_ci else 8288c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_MS_16LE; 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci case 24: 8318c2ecf20Sopenharmony_ci if (format->interleave == 2) 8328c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SS_24LE; 8338c2ecf20Sopenharmony_ci else 8348c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_MS_24LE; 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci case 32: 8378c2ecf20Sopenharmony_ci if (format->interleave == 2) 8388c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_SS_32LE; 8398c2ecf20Sopenharmony_ci else 8408c2ecf20Sopenharmony_ci dsp_format = DSP_AUDIOFORM_MS_32LE; 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 8458c2ecf20Sopenharmony_ci "set_audio_format[%d] = %x\n", pipe_index, dsp_format); 8468c2ecf20Sopenharmony_ci chip->comm_page->audio_format[pipe_index] = cpu_to_le16(dsp_format); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci/* start_transport starts transport for a set of pipes. 8528c2ecf20Sopenharmony_ciThe bits 1 in channel_mask specify what pipes to start. Only the bit of the 8538c2ecf20Sopenharmony_cifirst channel must be set, regardless its interleave. 8548c2ecf20Sopenharmony_ciSame thing for pause_ and stop_ -trasport below. */ 8558c2ecf20Sopenharmony_cistatic int start_transport(struct echoaudio *chip, u32 channel_mask, 8568c2ecf20Sopenharmony_ci u32 cyclic_mask) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 8608c2ecf20Sopenharmony_ci return -EIO; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci chip->comm_page->cmd_start |= cpu_to_le32(channel_mask); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (chip->comm_page->cmd_start) { 8658c2ecf20Sopenharmony_ci clear_handshake(chip); 8668c2ecf20Sopenharmony_ci send_vector(chip, DSP_VC_START_TRANSFER); 8678c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 8688c2ecf20Sopenharmony_ci return -EIO; 8698c2ecf20Sopenharmony_ci /* Keep track of which pipes are transporting */ 8708c2ecf20Sopenharmony_ci chip->active_mask |= channel_mask; 8718c2ecf20Sopenharmony_ci chip->comm_page->cmd_start = 0; 8728c2ecf20Sopenharmony_ci return 0; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "start_transport: No pipes to start!\n"); 8768c2ecf20Sopenharmony_ci return -EINVAL; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int pause_transport(struct echoaudio *chip, u32 channel_mask) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 8858c2ecf20Sopenharmony_ci return -EIO; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci chip->comm_page->cmd_stop |= cpu_to_le32(channel_mask); 8888c2ecf20Sopenharmony_ci chip->comm_page->cmd_reset = 0; 8898c2ecf20Sopenharmony_ci if (chip->comm_page->cmd_stop) { 8908c2ecf20Sopenharmony_ci clear_handshake(chip); 8918c2ecf20Sopenharmony_ci send_vector(chip, DSP_VC_STOP_TRANSFER); 8928c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 8938c2ecf20Sopenharmony_ci return -EIO; 8948c2ecf20Sopenharmony_ci /* Keep track of which pipes are transporting */ 8958c2ecf20Sopenharmony_ci chip->active_mask &= ~channel_mask; 8968c2ecf20Sopenharmony_ci chip->comm_page->cmd_stop = 0; 8978c2ecf20Sopenharmony_ci chip->comm_page->cmd_reset = 0; 8988c2ecf20Sopenharmony_ci return 0; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "pause_transport: No pipes to stop!\n"); 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic int stop_transport(struct echoaudio *chip, u32 channel_mask) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 9118c2ecf20Sopenharmony_ci return -EIO; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci chip->comm_page->cmd_stop |= cpu_to_le32(channel_mask); 9148c2ecf20Sopenharmony_ci chip->comm_page->cmd_reset |= cpu_to_le32(channel_mask); 9158c2ecf20Sopenharmony_ci if (chip->comm_page->cmd_reset) { 9168c2ecf20Sopenharmony_ci clear_handshake(chip); 9178c2ecf20Sopenharmony_ci send_vector(chip, DSP_VC_STOP_TRANSFER); 9188c2ecf20Sopenharmony_ci if (wait_handshake(chip)) 9198c2ecf20Sopenharmony_ci return -EIO; 9208c2ecf20Sopenharmony_ci /* Keep track of which pipes are transporting */ 9218c2ecf20Sopenharmony_ci chip->active_mask &= ~channel_mask; 9228c2ecf20Sopenharmony_ci chip->comm_page->cmd_stop = 0; 9238c2ecf20Sopenharmony_ci chip->comm_page->cmd_reset = 0; 9248c2ecf20Sopenharmony_ci return 0; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "stop_transport: No pipes to stop!\n"); 9288c2ecf20Sopenharmony_ci return 0; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic inline int is_pipe_allocated(struct echoaudio *chip, u16 pipe_index) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci return (chip->pipe_alloc_mask & (1 << pipe_index)); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci/* Stops everything and turns off the DSP. All pipes should be already 9418c2ecf20Sopenharmony_cistopped and unallocated. */ 9428c2ecf20Sopenharmony_cistatic int rest_in_peace(struct echoaudio *chip) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci /* Stops all active pipes (just to be sure) */ 9468c2ecf20Sopenharmony_ci stop_transport(chip, chip->active_mask); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci set_meters_on(chip, false); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_MIDI 9518c2ecf20Sopenharmony_ci enable_midi_input(chip, false); 9528c2ecf20Sopenharmony_ci#endif 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci /* Go to sleep */ 9558c2ecf20Sopenharmony_ci if (chip->dsp_code) { 9568c2ecf20Sopenharmony_ci /* Make load_firmware do a complete reload */ 9578c2ecf20Sopenharmony_ci chip->dsp_code = NULL; 9588c2ecf20Sopenharmony_ci /* Put the DSP to sleep */ 9598c2ecf20Sopenharmony_ci return send_vector(chip, DSP_VC_GO_COMATOSE); 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci return 0; 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci/* Fills the comm page with default values */ 9678c2ecf20Sopenharmony_cistatic int init_dsp_comm_page(struct echoaudio *chip) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci /* Check if the compiler added extra padding inside the structure */ 9708c2ecf20Sopenharmony_ci if (offsetof(struct comm_page, midi_output) != 0xbe0) { 9718c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 9728c2ecf20Sopenharmony_ci "init_dsp_comm_page() - Invalid struct comm_page structure\n"); 9738c2ecf20Sopenharmony_ci return -EPERM; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* Init all the basic stuff */ 9778c2ecf20Sopenharmony_ci chip->card_name = ECHOCARD_NAME; 9788c2ecf20Sopenharmony_ci chip->bad_board = true; /* Set true until DSP loaded */ 9798c2ecf20Sopenharmony_ci chip->dsp_code = NULL; /* Current DSP code not loaded */ 9808c2ecf20Sopenharmony_ci chip->asic_loaded = false; 9818c2ecf20Sopenharmony_ci memset(chip->comm_page, 0, sizeof(struct comm_page)); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* Init the comm page */ 9848c2ecf20Sopenharmony_ci chip->comm_page->comm_size = 9858c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(struct comm_page)); 9868c2ecf20Sopenharmony_ci chip->comm_page->handshake = cpu_to_le32(0xffffffff); 9878c2ecf20Sopenharmony_ci chip->comm_page->midi_out_free_count = 9888c2ecf20Sopenharmony_ci cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE); 9898c2ecf20Sopenharmony_ci chip->comm_page->sample_rate = cpu_to_le32(44100); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* Set line levels so we don't blast any inputs on startup */ 9928c2ecf20Sopenharmony_ci memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE); 9938c2ecf20Sopenharmony_ci memset(chip->comm_page->vmixer, ECHOGAIN_MUTED, VMIXER_ARRAY_SIZE); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return 0; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci/* This function initializes the chip structure with default values, ie. all 10018c2ecf20Sopenharmony_ci * muted and internal clock source. Then it copies the settings to the DSP. 10028c2ecf20Sopenharmony_ci * This MUST be called after the DSP is up and running ! 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_cistatic int init_line_levels(struct echoaudio *chip) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain)); 10078c2ecf20Sopenharmony_ci memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain)); 10088c2ecf20Sopenharmony_ci memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain)); 10098c2ecf20Sopenharmony_ci memset(chip->vmixer_gain, ECHOGAIN_MUTED, sizeof(chip->vmixer_gain)); 10108c2ecf20Sopenharmony_ci chip->input_clock = ECHO_CLOCK_INTERNAL; 10118c2ecf20Sopenharmony_ci chip->output_clock = ECHO_CLOCK_WORD; 10128c2ecf20Sopenharmony_ci chip->sample_rate = 44100; 10138c2ecf20Sopenharmony_ci return restore_dsp_rettings(chip); 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci/* This is low level part of the interrupt handler. 10198c2ecf20Sopenharmony_ciIt returns -1 if the IRQ is not ours, or N>=0 if it is, where N is the number 10208c2ecf20Sopenharmony_ciof midi data in the input queue. */ 10218c2ecf20Sopenharmony_cistatic int service_irq(struct echoaudio *chip) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci int st; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* Read the DSP status register and see if this DSP generated this interrupt */ 10268c2ecf20Sopenharmony_ci if (get_dsp_register(chip, CHI32_STATUS_REG) & CHI32_STATUS_IRQ) { 10278c2ecf20Sopenharmony_ci st = 0; 10288c2ecf20Sopenharmony_ci#ifdef ECHOCARD_HAS_MIDI 10298c2ecf20Sopenharmony_ci /* Get and parse midi data if present */ 10308c2ecf20Sopenharmony_ci if (chip->comm_page->midi_input[0]) /* The count is at index 0 */ 10318c2ecf20Sopenharmony_ci st = midi_service_irq(chip); /* Returns how many midi bytes we received */ 10328c2ecf20Sopenharmony_ci#endif 10338c2ecf20Sopenharmony_ci /* Clear the hardware interrupt */ 10348c2ecf20Sopenharmony_ci chip->comm_page->midi_input[0] = 0; 10358c2ecf20Sopenharmony_ci send_vector(chip, DSP_VC_ACK_INT); 10368c2ecf20Sopenharmony_ci return st; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci return -1; 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci/****************************************************************************** 10458c2ecf20Sopenharmony_ci Functions for opening and closing pipes 10468c2ecf20Sopenharmony_ci ******************************************************************************/ 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci/* allocate_pipes is used to reserve audio pipes for your exclusive use. 10498c2ecf20Sopenharmony_ciThe call will fail if some pipes are already allocated. */ 10508c2ecf20Sopenharmony_cistatic int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe, 10518c2ecf20Sopenharmony_ci int pipe_index, int interleave) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci int i; 10548c2ecf20Sopenharmony_ci u32 channel_mask; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 10578c2ecf20Sopenharmony_ci "allocate_pipes: ch=%d int=%d\n", pipe_index, interleave); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (chip->bad_board) 10608c2ecf20Sopenharmony_ci return -EIO; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci for (channel_mask = i = 0; i < interleave; i++) 10638c2ecf20Sopenharmony_ci channel_mask |= 1 << (pipe_index + i); 10648c2ecf20Sopenharmony_ci if (chip->pipe_alloc_mask & channel_mask) { 10658c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 10668c2ecf20Sopenharmony_ci "allocate_pipes: channel already open\n"); 10678c2ecf20Sopenharmony_ci return -EAGAIN; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci chip->comm_page->position[pipe_index] = 0; 10718c2ecf20Sopenharmony_ci chip->pipe_alloc_mask |= channel_mask; 10728c2ecf20Sopenharmony_ci /* This driver uses cyclic buffers only */ 10738c2ecf20Sopenharmony_ci chip->pipe_cyclic_mask |= channel_mask; 10748c2ecf20Sopenharmony_ci pipe->index = pipe_index; 10758c2ecf20Sopenharmony_ci pipe->interleave = interleave; 10768c2ecf20Sopenharmony_ci pipe->state = PIPE_STATE_STOPPED; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* The counter register is where the DSP writes the 32 bit DMA 10798c2ecf20Sopenharmony_ci position for a pipe. The DSP is constantly updating this value as 10808c2ecf20Sopenharmony_ci it moves data. The DMA counter is in units of bytes, not samples. */ 10818c2ecf20Sopenharmony_ci pipe->dma_counter = (__le32 *)&chip->comm_page->position[pipe_index]; 10828c2ecf20Sopenharmony_ci *pipe->dma_counter = 0; 10838c2ecf20Sopenharmony_ci return pipe_index; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic int free_pipes(struct echoaudio *chip, struct audiopipe *pipe) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci u32 channel_mask; 10918c2ecf20Sopenharmony_ci int i; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (snd_BUG_ON(!is_pipe_allocated(chip, pipe->index))) 10948c2ecf20Sopenharmony_ci return -EINVAL; 10958c2ecf20Sopenharmony_ci if (snd_BUG_ON(pipe->state != PIPE_STATE_STOPPED)) 10968c2ecf20Sopenharmony_ci return -EINVAL; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci for (channel_mask = i = 0; i < pipe->interleave; i++) 10998c2ecf20Sopenharmony_ci channel_mask |= 1 << (pipe->index + i); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci chip->pipe_alloc_mask &= ~channel_mask; 11028c2ecf20Sopenharmony_ci chip->pipe_cyclic_mask &= ~channel_mask; 11038c2ecf20Sopenharmony_ci return 0; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci/****************************************************************************** 11098c2ecf20Sopenharmony_ci Functions for managing the scatter-gather list 11108c2ecf20Sopenharmony_ci******************************************************************************/ 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic int sglist_init(struct echoaudio *chip, struct audiopipe *pipe) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci pipe->sglist_head = 0; 11158c2ecf20Sopenharmony_ci memset(pipe->sgpage.area, 0, PAGE_SIZE); 11168c2ecf20Sopenharmony_ci chip->comm_page->sglist_addr[pipe->index].addr = 11178c2ecf20Sopenharmony_ci cpu_to_le32(pipe->sgpage.addr); 11188c2ecf20Sopenharmony_ci return 0; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int sglist_add_mapping(struct echoaudio *chip, struct audiopipe *pipe, 11248c2ecf20Sopenharmony_ci dma_addr_t address, size_t length) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci int head = pipe->sglist_head; 11278c2ecf20Sopenharmony_ci struct sg_entry *list = (struct sg_entry *)pipe->sgpage.area; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (head < MAX_SGLIST_ENTRIES - 1) { 11308c2ecf20Sopenharmony_ci list[head].addr = cpu_to_le32(address); 11318c2ecf20Sopenharmony_ci list[head].size = cpu_to_le32(length); 11328c2ecf20Sopenharmony_ci pipe->sglist_head++; 11338c2ecf20Sopenharmony_ci } else { 11348c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "SGlist: too many fragments\n"); 11358c2ecf20Sopenharmony_ci return -ENOMEM; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci return 0; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_cistatic inline int sglist_add_irq(struct echoaudio *chip, struct audiopipe *pipe) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci return sglist_add_mapping(chip, pipe, 0, 0); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic inline int sglist_wrap(struct echoaudio *chip, struct audiopipe *pipe) 11508c2ecf20Sopenharmony_ci{ 11518c2ecf20Sopenharmony_ci return sglist_add_mapping(chip, pipe, pipe->sgpage.addr, 0); 11528c2ecf20Sopenharmony_ci} 1153