Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/asihpi/hpidspcd.c
26451 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/***********************************************************************
3
4
AudioScience HPI driver
5
Functions for reading DSP code using hotplug firmware loader
6
7
Copyright (C) 1997-2014 AudioScience Inc. <[email protected]>
8
9
10
***********************************************************************/
11
#define SOURCEFILE_NAME "hpidspcd.c"
12
#include "hpidspcd.h"
13
#include "hpidebug.h"
14
#include "hpi_version.h"
15
16
struct dsp_code_private {
17
/** Firmware descriptor */
18
const struct firmware *firmware;
19
struct pci_dev *dev;
20
};
21
22
/*-------------------------------------------------------------------*/
23
short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
24
u32 *os_error_code)
25
{
26
const struct firmware *firmware;
27
struct pci_dev *dev = os_data;
28
struct code_header header;
29
char fw_name[20];
30
short err_ret = HPI_ERROR_DSP_FILE_NOT_FOUND;
31
int err;
32
33
sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
34
35
err = request_firmware(&firmware, fw_name, &dev->dev);
36
37
if (err || !firmware) {
38
dev_err(&dev->dev, "%d, request_firmware failed for %s\n",
39
err, fw_name);
40
goto error1;
41
}
42
if (firmware->size < sizeof(header)) {
43
dev_err(&dev->dev, "Header size too small %s\n", fw_name);
44
goto error2;
45
}
46
memcpy(&header, firmware->data, sizeof(header));
47
48
if ((header.type != 0x45444F43) || /* "CODE" */
49
(header.adapter != adapter)
50
|| (header.size != firmware->size)) {
51
dev_err(&dev->dev,
52
"Invalid firmware header size %d != file %zd\n",
53
header.size, firmware->size);
54
goto error2;
55
}
56
57
if (HPI_VER_MAJOR(header.version) != HPI_VER_MAJOR(HPI_VER)) {
58
/* Major version change probably means Host-DSP protocol change */
59
dev_err(&dev->dev,
60
"Incompatible firmware version DSP image %X != Driver %X\n",
61
header.version, HPI_VER);
62
goto error2;
63
}
64
65
if (header.version != HPI_VER) {
66
dev_warn(&dev->dev,
67
"Firmware version mismatch: DSP image %X != Driver %X\n",
68
header.version, HPI_VER);
69
}
70
71
HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
72
dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL);
73
if (!dsp_code->pvt) {
74
err_ret = HPI_ERROR_MEMORY_ALLOC;
75
goto error2;
76
}
77
78
dsp_code->pvt->dev = dev;
79
dsp_code->pvt->firmware = firmware;
80
dsp_code->header = header;
81
dsp_code->block_length = header.size / sizeof(u32);
82
dsp_code->word_count = sizeof(header) / sizeof(u32);
83
return 0;
84
85
error2:
86
release_firmware(firmware);
87
error1:
88
dsp_code->block_length = 0;
89
return err_ret;
90
}
91
92
/*-------------------------------------------------------------------*/
93
void hpi_dsp_code_close(struct dsp_code *dsp_code)
94
{
95
HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
96
release_firmware(dsp_code->pvt->firmware);
97
kfree(dsp_code->pvt);
98
}
99
100
/*-------------------------------------------------------------------*/
101
void hpi_dsp_code_rewind(struct dsp_code *dsp_code)
102
{
103
/* Go back to start of data, after header */
104
dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
105
}
106
107
/*-------------------------------------------------------------------*/
108
short hpi_dsp_code_read_word(struct dsp_code *dsp_code, u32 *pword)
109
{
110
if (dsp_code->word_count + 1 > dsp_code->block_length)
111
return HPI_ERROR_DSP_FILE_FORMAT;
112
113
*pword = ((u32 *)(dsp_code->pvt->firmware->data))[dsp_code->
114
word_count];
115
dsp_code->word_count++;
116
return 0;
117
}
118
119
/*-------------------------------------------------------------------*/
120
short hpi_dsp_code_read_block(size_t words_requested,
121
struct dsp_code *dsp_code, u32 **ppblock)
122
{
123
if (dsp_code->word_count + words_requested > dsp_code->block_length)
124
return HPI_ERROR_DSP_FILE_FORMAT;
125
126
*ppblock =
127
((u32 *)(dsp_code->pvt->firmware->data)) +
128
dsp_code->word_count;
129
dsp_code->word_count += words_requested;
130
return 0;
131
}
132
133