blob: 3603c24f34d2d9a632223480fd5ec0d06023dd8b [file] [log] [blame]
Eliot Blennerhassett43986432014-12-18 17:57:13 +13001/***********************************************************************
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002
3 AudioScience HPI driver
Eliot Blennerhassett43986432014-12-18 17:57:13 +13004 Functions for reading DSP code using hotplug firmware loader
5
6 Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of version 2 of the GNU General Public License as
10 published by the Free Software Foundation;
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
Eliot Blennerhassett43986432014-12-18 17:57:13 +130021***********************************************************************/
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020022#define SOURCEFILE_NAME "hpidspcd.c"
23#include "hpidspcd.h"
24#include "hpidebug.h"
Eliot Blennerhassettf6baaec2011-12-22 13:38:31 +130025#include "hpi_version.h"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020026
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120027struct dsp_code_private {
28 /** Firmware descriptor */
29 const struct firmware *firmware;
30 struct pci_dev *dev;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020031};
32
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020033/*-------------------------------------------------------------------*/
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120034short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
35 u32 *os_error_code)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020036{
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120037 const struct firmware *firmware;
38 struct pci_dev *dev = os_data;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020039 struct code_header header;
40 char fw_name[20];
Jesper Juhldc889f12011-07-31 23:16:43 +020041 short err_ret = HPI_ERROR_DSP_FILE_NOT_FOUND;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020042 int err;
43
44 sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020045
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120046 err = request_firmware(&firmware, fw_name, &dev->dev);
Eliot Blennerhassett5ed15da2011-02-10 17:25:54 +130047
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120048 if (err || !firmware) {
Joe Perches4ee3bff2012-10-28 01:05:54 -070049 dev_err(&dev->dev, "%d, request_firmware failed for %s\n",
50 err, fw_name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020051 goto error1;
52 }
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120053 if (firmware->size < sizeof(header)) {
Joe Perches4ee3bff2012-10-28 01:05:54 -070054 dev_err(&dev->dev, "Header size too small %s\n", fw_name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020055 goto error2;
56 }
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120057 memcpy(&header, firmware->data, sizeof(header));
58
59 if ((header.type != 0x45444F43) || /* "CODE" */
60 (header.adapter != adapter)
61 || (header.size != firmware->size)) {
Joe Perches4ee3bff2012-10-28 01:05:54 -070062 dev_err(&dev->dev,
Eliot Blennerhassettf6baaec2011-12-22 13:38:31 +130063 "Invalid firmware header size %d != file %zd\n",
64 header.size, firmware->size);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020065 goto error2;
66 }
67
Eliot Blennerhassett43986432014-12-18 17:57:13 +130068 if (HPI_VER_MAJOR(header.version) != HPI_VER_MAJOR(HPI_VER)) {
69 /* Major version change probably means Host-DSP protocol change */
70 dev_err(&dev->dev,
71 "Incompatible firmware version DSP image %X != Driver %X\n",
Joe Perches4ee3bff2012-10-28 01:05:54 -070072 header.version, HPI_VER);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020073 goto error2;
74 }
75
Eliot Blennerhassettf6baaec2011-12-22 13:38:31 +130076 if (header.version != HPI_VER) {
Eliot Blennerhassett43986432014-12-18 17:57:13 +130077 dev_warn(&dev->dev,
78 "Firmware version mismatch: DSP image %X != Driver %X\n",
79 header.version, HPI_VER);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020080 }
81
Eliot Blennerhassett5ed15da2011-02-10 17:25:54 +130082 HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120083 dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL);
Jesper Juhldc889f12011-07-31 23:16:43 +020084 if (!dsp_code->pvt) {
85 err_ret = HPI_ERROR_MEMORY_ALLOC;
86 goto error2;
87 }
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120088
89 dsp_code->pvt->dev = dev;
90 dsp_code->pvt->firmware = firmware;
91 dsp_code->header = header;
92 dsp_code->block_length = header.size / sizeof(u32);
93 dsp_code->word_count = sizeof(header) / sizeof(u32);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020094 return 0;
95
96error2:
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120097 release_firmware(firmware);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020098error1:
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +120099 dsp_code->block_length = 0;
Jesper Juhldc889f12011-07-31 23:16:43 +0200100 return err_ret;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200101}
102
103/*-------------------------------------------------------------------*/
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200104void hpi_dsp_code_close(struct dsp_code *dsp_code)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200105{
Eliot Blennerhassett50d5f772011-12-22 13:38:44 +1300106 HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
107 release_firmware(dsp_code->pvt->firmware);
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200108 kfree(dsp_code->pvt);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200109}
110
111/*-------------------------------------------------------------------*/
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200112void hpi_dsp_code_rewind(struct dsp_code *dsp_code)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200113{
114 /* Go back to start of data, after header */
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200115 dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200116}
117
118/*-------------------------------------------------------------------*/
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200119short hpi_dsp_code_read_word(struct dsp_code *dsp_code, u32 *pword)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200120{
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200121 if (dsp_code->word_count + 1 > dsp_code->block_length)
Eliot Blennerhassett5ed15da2011-02-10 17:25:54 +1300122 return HPI_ERROR_DSP_FILE_FORMAT;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200123
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200124 *pword = ((u32 *)(dsp_code->pvt->firmware->data))[dsp_code->
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200125 word_count];
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200126 dsp_code->word_count++;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200127 return 0;
128}
129
130/*-------------------------------------------------------------------*/
131short hpi_dsp_code_read_block(size_t words_requested,
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200132 struct dsp_code *dsp_code, u32 **ppblock)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200133{
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200134 if (dsp_code->word_count + words_requested > dsp_code->block_length)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200135 return HPI_ERROR_DSP_FILE_FORMAT;
136
137 *ppblock =
Eliot Blennerhassett95a4c6e2011-07-22 15:52:42 +1200138 ((u32 *)(dsp_code->pvt->firmware->data)) +
139 dsp_code->word_count;
140 dsp_code->word_count += words_requested;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200141 return 0;
142}