ALSA: asihpi - DSP code loader API now independent of OS

The loader API has been revised so that OS specific data is kept
local to hpidspcd.c, and the public API is unchanged across OSes.

Signed-off-by: Eliot Blennerhassett <eblennerhassett@audioscience.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Eliot Blennerhassett 2011-07-22 15:52:42 +12:00 committed by Takashi Iwai
parent 58fbf77ff5
commit 95a4c6e785
4 changed files with 97 additions and 122 deletions

View File

@ -946,11 +946,8 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
} }
/* write the DSP code down into the DSPs memory */ /* write the DSP code down into the DSPs memory */
/*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */ error = hpi_dsp_code_open(boot_load_family, pao->pci.pci_dev,
dsp_code.ps_dev = pao->pci.pci_dev; &dsp_code, pos_error_code);
error = hpi_dsp_code_open(boot_load_family, &dsp_code,
pos_error_code);
if (error) if (error)
return error; return error;

View File

@ -1371,9 +1371,8 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
return err; return err;
/* write the DSP code down into the DSPs memory */ /* write the DSP code down into the DSPs memory */
dsp_code.ps_dev = pao->pci.pci_dev; err = hpi_dsp_code_open(boot_code_id[dsp], pao->pci.pci_dev,
err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code, &dsp_code, pos_error_code);
pos_error_code);
if (err) if (err)
return err; return err;

View File

@ -1,8 +1,8 @@
/***********************************************************************/ /***********************************************************************/
/*! /**
AudioScience HPI driver AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as it under the terms of version 2 of the GNU General Public License as
@ -18,90 +18,60 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\file \file
Functions for reading DSP code to load into DSP Functions for reading DSP code using
(Linux only:) If DSPCODE_FIRMWARE_LOADER is defined, code is read using
hotplug firmware loader from individual dsp code files hotplug firmware loader from individual dsp code files
*/
If neither of the above is defined, code is read from linked arrays.
DSPCODE_ARRAY is defined.
HPI_INCLUDE_**** must be defined
and the appropriate hzz?????.c or hex?????.c linked in
*/
/***********************************************************************/ /***********************************************************************/
#define SOURCEFILE_NAME "hpidspcd.c" #define SOURCEFILE_NAME "hpidspcd.c"
#include "hpidspcd.h" #include "hpidspcd.h"
#include "hpidebug.h" #include "hpidebug.h"
/** struct dsp_code_private {
Header structure for binary dsp code file (see asidsp.doc) /** Firmware descriptor */
This structure must match that used in s2bin.c for generation of asidsp.bin const struct firmware *firmware;
*/ struct pci_dev *dev;
#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(push, 1)
#endif
struct code_header {
u32 size;
char type[4];
u32 adapter;
u32 version;
u32 crc;
}; };
#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(pop)
#endif
#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \ #define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER))) HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
/***********************************************************************/
#include <linux/pci.h> #include <linux/pci.h>
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code, short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
u32 *pos_error_code) u32 *os_error_code)
{ {
const struct firmware *ps_firmware = ps_dsp_code->ps_firmware; const struct firmware *firmware;
struct pci_dev *dev = os_data;
struct code_header header; struct code_header header;
char fw_name[20]; char fw_name[20];
int err; int err;
sprintf(fw_name, "asihpi/dsp%04x.bin", adapter); sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
err = request_firmware(&ps_firmware, fw_name, err = request_firmware(&firmware, fw_name, &dev->dev);
&ps_dsp_code->ps_dev->dev);
if (err != 0) { if (err || !firmware) {
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, dev_printk(KERN_ERR, &dev->dev,
"%d, request_firmware failed for %s\n", err, "%d, request_firmware failed for %s\n", err,
fw_name); fw_name);
goto error1; goto error1;
} }
if (ps_firmware->size < sizeof(header)) { if (firmware->size < sizeof(header)) {
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, dev_printk(KERN_ERR, &dev->dev, "Header size too small %s\n",
"Header size too small %s\n", fw_name); fw_name);
goto error2; goto error2;
} }
memcpy(&header, ps_firmware->data, sizeof(header)); memcpy(&header, firmware->data, sizeof(header));
if (header.adapter != adapter) {
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, if ((header.type != 0x45444F43) || /* "CODE" */
"Adapter type incorrect %4x != %4x\n", header.adapter, (header.adapter != adapter)
adapter); || (header.size != firmware->size)) {
goto error2; dev_printk(KERN_ERR, &dev->dev, "Invalid firmware file\n");
}
if (header.size != ps_firmware->size) {
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
"Code size wrong %d != %ld\n", header.size,
(unsigned long)ps_firmware->size);
goto error2; goto error2;
} }
if (header.version / 100 != HPI_VER_DECIMAL / 100) { if ((header.version / 100 & ~1) != (HPI_VER_DECIMAL / 100 & ~1)) {
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, dev_printk(KERN_ERR, &dev->dev,
"Incompatible firmware version " "Incompatible firmware version "
"DSP image %d != Driver %d\n", header.version, "DSP image %d != Driver %d\n", header.version,
HPI_VER_DECIMAL); HPI_VER_DECIMAL);
@ -109,67 +79,70 @@ short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
} }
if (header.version != HPI_VER_DECIMAL) { if (header.version != HPI_VER_DECIMAL) {
dev_printk(KERN_WARNING, &ps_dsp_code->ps_dev->dev, dev_printk(KERN_WARNING, &dev->dev,
"Firmware: release version mismatch DSP image %d != Driver %d\n", "Firmware: release version mismatch DSP image %d != Driver %d\n",
header.version, HPI_VER_DECIMAL); header.version, HPI_VER_DECIMAL);
} }
HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name); HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
ps_dsp_code->ps_firmware = ps_firmware; dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL);
ps_dsp_code->block_length = header.size / sizeof(u32); if (!dsp_code->pvt)
ps_dsp_code->word_count = sizeof(header) / sizeof(u32); return HPI_ERROR_MEMORY_ALLOC;
ps_dsp_code->version = header.version;
ps_dsp_code->crc = header.crc; dsp_code->pvt->dev = dev;
dsp_code->pvt->firmware = firmware;
dsp_code->header = header;
dsp_code->block_length = header.size / sizeof(u32);
dsp_code->word_count = sizeof(header) / sizeof(u32);
return 0; return 0;
error2: error2:
release_firmware(ps_firmware); release_firmware(firmware);
error1: error1:
ps_dsp_code->ps_firmware = NULL; dsp_code->block_length = 0;
ps_dsp_code->block_length = 0;
return HPI_ERROR_DSP_FILE_NOT_FOUND; return HPI_ERROR_DSP_FILE_NOT_FOUND;
} }
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
void hpi_dsp_code_close(struct dsp_code *ps_dsp_code) void hpi_dsp_code_close(struct dsp_code *dsp_code)
{ {
if (ps_dsp_code->ps_firmware != NULL) { if (dsp_code->pvt->firmware) {
HPI_DEBUG_LOG(DEBUG, "dsp code closed\n"); HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
release_firmware(ps_dsp_code->ps_firmware); release_firmware(dsp_code->pvt->firmware);
ps_dsp_code->ps_firmware = NULL; dsp_code->pvt->firmware = NULL;
} }
kfree(dsp_code->pvt);
} }
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code) void hpi_dsp_code_rewind(struct dsp_code *dsp_code)
{ {
/* Go back to start of data, after header */ /* Go back to start of data, after header */
ps_dsp_code->word_count = sizeof(struct code_header) / sizeof(u32); dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
} }
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword) short hpi_dsp_code_read_word(struct dsp_code *dsp_code, u32 *pword)
{ {
if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length) if (dsp_code->word_count + 1 > dsp_code->block_length)
return HPI_ERROR_DSP_FILE_FORMAT; return HPI_ERROR_DSP_FILE_FORMAT;
*pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code-> *pword = ((u32 *)(dsp_code->pvt->firmware->data))[dsp_code->
word_count]; word_count];
ps_dsp_code->word_count++; dsp_code->word_count++;
return 0; return 0;
} }
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
short hpi_dsp_code_read_block(size_t words_requested, short hpi_dsp_code_read_block(size_t words_requested,
struct dsp_code *ps_dsp_code, u32 **ppblock) struct dsp_code *dsp_code, u32 **ppblock)
{ {
if (ps_dsp_code->word_count + words_requested > if (dsp_code->word_count + words_requested > dsp_code->block_length)
ps_dsp_code->block_length)
return HPI_ERROR_DSP_FILE_FORMAT; return HPI_ERROR_DSP_FILE_FORMAT;
*ppblock = *ppblock =
((u32 *)(ps_dsp_code->ps_firmware->data)) + ((u32 *)(dsp_code->pvt->firmware->data)) +
ps_dsp_code->word_count; dsp_code->word_count;
ps_dsp_code->word_count += words_requested; dsp_code->word_count += words_requested;
return 0; return 0;
} }

View File

@ -2,7 +2,7 @@
/** /**
AudioScience HPI driver AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as it under the terms of version 2 of the GNU General Public License as
@ -20,19 +20,6 @@
\file \file
Functions for reading DSP code to load into DSP Functions for reading DSP code to load into DSP
hpi_dspcode_defines HPI DSP code loading method
Define exactly one of these to select how the DSP code is supplied to
the adapter.
End users writing applications that use the HPI interface do not have to
use any of the below defines; they are only necessary for building drivers
HPI_DSPCODE_FILE:
DSP code is supplied as a file that is opened and read from by the driver.
HPI_DSPCODE_FIRMWARE:
DSP code is read using the hotplug firmware loader module.
Only valid when compiling the HPI kernel driver under Linux.
*/ */
/***********************************************************************/ /***********************************************************************/
#ifndef _HPIDSPCD_H_ #ifndef _HPIDSPCD_H_
@ -40,37 +27,56 @@ DSP code is read using the hotplug firmware loader module.
#include "hpi_internal.h" #include "hpi_internal.h"
#ifndef DISABLE_PRAGMA_PACK1 /** Code header version is decimal encoded e.g. 4.06.10 is 40601 */
#pragma pack(push, 1) #define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
#endif HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
/** Header structure for dsp firmware file
This structure must match that used in s2bin.c for generation of asidsp.bin
*/
/*#ifndef DISABLE_PRAGMA_PACK1 */
/*#pragma pack(push, 1) */
/*#endif */
struct code_header {
/** Size in bytes including header */
u32 size;
/** File type tag "CODE" == 0x45444F43 */
u32 type;
/** Adapter model number */
u32 adapter;
/** Firmware version*/
u32 version;
/** Data checksum */
u32 checksum;
};
/*#ifndef DISABLE_PRAGMA_PACK1 */
/*#pragma pack(pop) */
/*#endif */
/*? Don't need the pragmas? */
compile_time_assert((sizeof(struct code_header) == 20), code_header_size);
/** Descriptor for dspcode from firmware loader */ /** Descriptor for dspcode from firmware loader */
struct dsp_code { struct dsp_code {
/** Firmware descriptor */ /** copy of file header */
const struct firmware *ps_firmware; struct code_header header;
struct pci_dev *ps_dev;
/** Expected number of words in the whole dsp code,INCL header */ /** Expected number of words in the whole dsp code,INCL header */
long int block_length; u32 block_length;
/** Number of words read so far */ /** Number of words read so far */
long int word_count; u32 word_count;
/** Version read from dsp code file */
u32 version; /** internal state of DSP code reader */
/** CRC read from dsp code file */ struct dsp_code_private *pvt;
u32 crc;
}; };
#ifndef DISABLE_PRAGMA_PACK1 /** Prepare *psDspCode to refer to the requested adapter's firmware.
#pragma pack(pop) Code file name is obtained from HpiOs_GetDspCodePath
#endif
/** Prepare *psDspCode to refer to the requuested adapter.
Searches the file, or selects the appropriate linked array
\return 0 for success, or error code if requested code is not available \return 0 for success, or error code if requested code is not available
*/ */
short hpi_dsp_code_open( short hpi_dsp_code_open(
/** Code identifier, usually adapter family */ /** Code identifier, usually adapter family */
u32 adapter, u32 adapter, void *pci_dev,
/** Pointer to DSP code control structure */ /** Pointer to DSP code control structure */
struct dsp_code *ps_dsp_code, struct dsp_code *ps_dsp_code,
/** Pointer to dword to receive OS specific error code */ /** Pointer to dword to receive OS specific error code */