ALSA: Add support of AudioScience ASI boards

Added the support of AudioScience ASI boards.
The driver has been tested for years on alsa-driver external tree,
now finally got merged to the kernel.

Signed-off-by: Eliot Blennerhassett <eblennerhassett@audioscience.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Eliot Blennerhassett 2010-04-21 18:17:39 +02:00 committed by Takashi Iwai
parent cf0dbba515
commit 719f82d398
27 changed files with 18429 additions and 0 deletions

View File

@ -227,6 +227,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported.
Module snd-asihpi
-----------------
Module for AudioScience ASI soundcards
enable_hpi_hwdep - enable HPI hwdep for AudioScience soundcard
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-atiixp
-----------------

View File

@ -58,6 +58,18 @@ config SND_ALI5451
To compile this driver as a module, choose M here: the module
will be called snd-ali5451.
config SND_ASIHPI
tristate "AudioScience ASIxxxx"
depends on X86
select FW_LOADER
select SND_PCM
select SND_HWDEP
help
Say Y here to include support for AudioScience ASI sound cards.
To compile this driver as a module, choose M here: the module
will be called snd-asihpi.
config SND_ATIIXP
tristate "ATI IXP AC97 Controller"
select SND_AC97_CODEC

View File

@ -57,6 +57,7 @@ obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o
obj-$(CONFIG_SND) += \
ac97/ \
ali5451/ \
asihpi/ \
au88x0/ \
aw2/ \
ctxfi/ \

View File

@ -0,0 +1,5 @@
snd-asihpi-objs := asihpi.o hpioctl.o hpimsginit.o\
hpicmn.o hpifunc.o hpidebug.o hpidspcd.o\
hpios.o hpi6000.o hpi6205.o hpimsgx.o
obj-$(CONFIG_SND_ASIHPI) += snd-asihpi.o

3002
sound/pci/asihpi/asihpi.c Normal file

File diff suppressed because it is too large Load Diff

2001
sound/pci/asihpi/hpi.h Normal file

File diff suppressed because it is too large Load Diff

1841
sound/pci/asihpi/hpi6000.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
/*****************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Public declarations for DSP Proramming Interface to TI C6701
Shared between hpi6000.c and DSP code
(C) Copyright AudioScience Inc. 1998-2003
******************************************************************************/
#ifndef _HPI6000_H_
#define _HPI6000_H_
#define HPI_NMIXER_CONTROLS 200
/*
* Control caching is always supported in the HPI code.
* The DSP should make sure that dwControlCacheSizeInBytes is initialized to 0
* during boot to make it in-active.
*/
struct hpi_hif_6000 {
u32 host_cmd;
u32 dsp_ack;
u32 address;
u32 length;
u32 message_buffer_address;
u32 response_buffer_address;
u32 dsp_number;
u32 adapter_info;
u32 control_cache_is_dirty;
u32 control_cache_address;
u32 control_cache_size_in_bytes;
u32 control_cache_count;
};
#define HPI_HIF_PACK_ADAPTER_INFO(adapter, version_major, version_minor) \
((adapter << 16) | (version_major << 8) | version_minor)
#define HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER(adapterinfo) \
((adapterinfo >> 16) & 0xffff)
#define HPI_HIF_ADAPTER_INFO_EXTRACT_HWVERSION_MAJOR(adapterinfo) \
((adapterinfo >> 8) & 0xff)
#define HPI_HIF_ADAPTER_INFO_EXTRACT_HWVERSION_MINOR(adapterinfo) \
(adapterinfo & 0xff)
/* Command/status exchanged between host and DSP */
#define HPI_HIF_IDLE 0
#define HPI_HIF_SEND_MSG 1
#define HPI_HIF_GET_RESP 2
#define HPI_HIF_DATA_MASK 0x10
#define HPI_HIF_SEND_DATA 0x13
#define HPI_HIF_GET_DATA 0x14
#define HPI_HIF_SEND_DONE 5
#define HPI_HIF_RESET 9
#endif /* _HPI6000_H_ */

2332
sound/pci/asihpi/hpi6205.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
/*****************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Host Interface module for an ASI6205 based
bus mastering PCI adapter.
Copyright AudioScience, Inc., 2003
******************************************************************************/
#ifndef _HPI6205_H_
#define _HPI6205_H_
/* transitional conditional compile shared between host and DSP */
/* #define HPI6205_NO_HSR_POLL */
#include "hpi_internal.h"
/***********************************************************
Defines used for basic messaging
************************************************************/
#define H620_HIF_RESET 0
#define H620_HIF_IDLE 1
#define H620_HIF_GET_RESP 2
#define H620_HIF_DATA_DONE 3
#define H620_HIF_DATA_MASK 0x10
#define H620_HIF_SEND_DATA 0x14
#define H620_HIF_GET_DATA 0x15
#define H620_HIF_UNKNOWN 0x0000ffff
/***********************************************************
Types used for mixer control caching
************************************************************/
#define H620_MAX_ISTREAMS 32
#define H620_MAX_OSTREAMS 32
#define HPI_NMIXER_CONTROLS 2048
/*********************************************************************
This is used for dynamic control cache allocation
**********************************************************************/
struct controlcache_6205 {
u32 number_of_controls;
u32 physical_address32;
u32 size_in_bytes;
};
/*********************************************************************
This is used for dynamic allocation of async event array
**********************************************************************/
struct async_event_buffer_6205 {
u32 physical_address32;
u32 spare;
struct hpi_fifo_buffer b;
};
/***********************************************************
The Host located memory buffer that the 6205 will bus master
in and out of.
************************************************************/
#define HPI6205_SIZEOF_DATA (16*1024)
struct bus_master_interface {
u32 host_cmd;
u32 dsp_ack;
u32 transfer_size_in_bytes;
union {
struct hpi_message message_buffer;
struct hpi_response response_buffer;
u8 b_data[HPI6205_SIZEOF_DATA];
} u;
struct controlcache_6205 control_cache;
struct async_event_buffer_6205 async_buffer;
struct hpi_hostbuffer_status
instream_host_buffer_status[H620_MAX_ISTREAMS];
struct hpi_hostbuffer_status
outstream_host_buffer_status[H620_MAX_OSTREAMS];
};
#endif

File diff suppressed because it is too large Load Diff

643
sound/pci/asihpi/hpicmn.c Normal file
View File

@ -0,0 +1,643 @@
/******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\file hpicmn.c
Common functions used by hpixxxx.c modules
(C) Copyright AudioScience Inc. 1998-2003
*******************************************************************************/
#define SOURCEFILE_NAME "hpicmn.c"
#include "hpi_internal.h"
#include "hpidebug.h"
#include "hpicmn.h"
struct hpi_adapters_list {
struct hpios_spinlock list_lock;
struct hpi_adapter_obj adapter[HPI_MAX_ADAPTERS];
u16 gw_num_adapters;
};
static struct hpi_adapters_list adapters;
/**
* Given an HPI Message that was sent out and a response that was received,
* validate that the response has the correct fields filled in,
* i.e ObjectType, Function etc
**/
u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
{
u16 error = 0;
if ((phr->type != HPI_TYPE_RESPONSE)
|| (phr->object != phm->object)
|| (phr->function != phm->function))
error = HPI_ERROR_INVALID_RESPONSE;
return error;
}
u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
{
u16 retval = 0;
/*HPI_ASSERT(pao->wAdapterType); */
hpios_alistlock_lock(&adapters);
if (pao->index >= HPI_MAX_ADAPTERS) {
retval = HPI_ERROR_BAD_ADAPTER_NUMBER;
goto unlock;
}
if (adapters.adapter[pao->index].adapter_type) {
{
retval = HPI_DUPLICATE_ADAPTER_NUMBER;
goto unlock;
}
}
adapters.adapter[pao->index] = *pao;
hpios_dsplock_init(&adapters.adapter[pao->index]);
adapters.gw_num_adapters++;
unlock:
hpios_alistlock_un_lock(&adapters);
return retval;
}
void hpi_delete_adapter(struct hpi_adapter_obj *pao)
{
memset(pao, 0, sizeof(struct hpi_adapter_obj));
hpios_alistlock_lock(&adapters);
adapters.gw_num_adapters--; /* dec the number of adapters */
hpios_alistlock_un_lock(&adapters);
}
/**
* FindAdapter returns a pointer to the struct hpi_adapter_obj with
* index wAdapterIndex in an HPI_ADAPTERS_LIST structure.
*
*/
struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
{
struct hpi_adapter_obj *pao = NULL;
if (adapter_index >= HPI_MAX_ADAPTERS) {
HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d ",
adapter_index);
return NULL;
}
pao = &adapters.adapter[adapter_index];
if (pao->adapter_type != 0) {
/*
HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n",
wAdapterIndex);
*/
return pao;
} else {
/*
HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n",
wAdapterIndex);
*/
return NULL;
}
}
/**
*
* wipe an HPI_ADAPTERS_LIST structure.
*
**/
static void wipe_adapter_list(void
)
{
memset(&adapters, 0, sizeof(adapters));
}
/**
* SubSysGetAdapters fills awAdapterList in an struct hpi_response structure
* with all adapters in the given HPI_ADAPTERS_LIST.
*
*/
static void subsys_get_adapters(struct hpi_response *phr)
{
/* fill in the response adapter array with the position */
/* identified by the adapter number/index of the adapters in */
/* this HPI */
/* i.e. if we have an A120 with it's jumper set to */
/* Adapter Number 2 then put an Adapter type A120 in the */
/* array in position 1 */
/* NOTE: AdapterNumber is 1..N, Index is 0..N-1 */
/* input: NONE */
/* output: wNumAdapters */
/* awAdapter[] */
/* */
short i;
struct hpi_adapter_obj *pao = NULL;
HPI_DEBUG_LOG(VERBOSE, "subsys_get_adapters\n");
/* for each adapter, place it's type in the position of the array */
/* corresponding to it's adapter number */
for (i = 0; i < adapters.gw_num_adapters; i++) {
pao = &adapters.adapter[i];
if (phr->u.s.aw_adapter_list[pao->index] != 0) {
phr->error = HPI_DUPLICATE_ADAPTER_NUMBER;
phr->specific_error = pao->index;
return;
}
phr->u.s.aw_adapter_list[pao->index] = pao->adapter_type;
}
phr->u.s.num_adapters = adapters.gw_num_adapters;
phr->error = 0; /* the function completed OK; */
}
static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
{
unsigned int i;
int cached = 0;
if (!pC)
return 0;
if ((!pC->init) && (pC->p_cache != NULL) && (pC->control_count)
&& (pC->cache_size_in_bytes)
) {
u32 *p_master_cache;
pC->init = 1;
p_master_cache = (u32 *)pC->p_cache;
HPI_DEBUG_LOG(VERBOSE, "check %d controls\n",
pC->control_count);
for (i = 0; i < pC->control_count; i++) {
struct hpi_control_cache_info *info =
(struct hpi_control_cache_info *)
p_master_cache;
if (info->control_type) {
pC->p_info[i] = info;
cached++;
} else
pC->p_info[i] = NULL;
if (info->size_in32bit_words)
p_master_cache += info->size_in32bit_words;
else
p_master_cache +=
sizeof(struct
hpi_control_cache_single) /
sizeof(u32);
HPI_DEBUG_LOG(VERBOSE,
"cached %d, pinfo %p index %d type %d\n",
cached, pC->p_info[i], info->control_index,
info->control_type);
}
/*
We didn't find anything to cache, so try again later !
*/
if (!cached)
pC->init = 0;
}
return pC->init;
}
/** Find a control.
*/
static short find_control(struct hpi_message *phm,
struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI,
u16 *pw_control_index)
{
*pw_control_index = phm->obj_index;
if (!control_cache_alloc_check(p_cache)) {
HPI_DEBUG_LOG(VERBOSE,
"control_cache_alloc_check() failed. adap%d ci%d\n",
phm->adapter_index, *pw_control_index);
return 0;
}
*pI = p_cache->p_info[*pw_control_index];
if (!*pI) {
HPI_DEBUG_LOG(VERBOSE, "uncached adap %d, control %d\n",
phm->adapter_index, *pw_control_index);
return 0;
} else {
HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
(*pI)->control_type);
}
return 1;
}
/** Used by the kernel driver to figure out if a buffer needs mapping.
*/
short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache,
struct hpi_message *phm, void **p, unsigned int *pN)
{
*pN = 0;
*p = NULL;
if ((phm->function == HPI_CONTROL_GET_STATE)
&& (phm->object == HPI_OBJ_CONTROLEX)
) {
u16 control_index;
struct hpi_control_cache_info *pI;
if (!find_control(phm, p_cache, &pI, &control_index))
return 0;
}
return 0;
}
/* allow unified treatment of several string fields within struct */
#define HPICMN_PAD_OFS_AND_SIZE(m) {\
offsetof(struct hpi_control_cache_pad, m), \
sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
struct pad_ofs_size {
unsigned int offset;
unsigned int field_size;
};
static struct pad_ofs_size pad_desc[] = {
HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */
HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */
HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */
HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */
};
/** CheckControlCache checks the cache and fills the struct hpi_response
* accordingly. It returns one if a cache hit occurred, zero otherwise.
*/
short hpi_check_control_cache(struct hpi_control_cache *p_cache,
struct hpi_message *phm, struct hpi_response *phr)
{
short found = 1;
u16 control_index;
struct hpi_control_cache_info *pI;
struct hpi_control_cache_single *pC;
struct hpi_control_cache_pad *p_pad;
if (!find_control(phm, p_cache, &pI, &control_index))
return 0;
phr->error = 0;
/* pC is the default cached control strucure. May be cast to
something else in the following switch statement.
*/
pC = (struct hpi_control_cache_single *)pI;
p_pad = (struct hpi_control_cache_pad *)pI;
switch (pI->control_type) {
case HPI_CONTROL_METER:
if (phm->u.c.attribute == HPI_METER_PEAK) {
phr->u.c.an_log_value[0] = pC->u.p.an_log_peak[0];
phr->u.c.an_log_value[1] = pC->u.p.an_log_peak[1];
} else if (phm->u.c.attribute == HPI_METER_RMS) {
phr->u.c.an_log_value[0] = pC->u.p.an_logRMS[0];
phr->u.c.an_log_value[1] = pC->u.p.an_logRMS[1];
} else
found = 0;
break;
case HPI_CONTROL_VOLUME:
if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
phr->u.c.an_log_value[0] = pC->u.v.an_log[0];
phr->u.c.an_log_value[1] = pC->u.v.an_log[1];
} else
found = 0;
break;
case HPI_CONTROL_MULTIPLEXER:
if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
phr->u.c.param1 = pC->u.x.source_node_type;
phr->u.c.param2 = pC->u.x.source_node_index;
} else {
found = 0;
}
break;
case HPI_CONTROL_CHANNEL_MODE:
if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
phr->u.c.param1 = pC->u.m.mode;
else
found = 0;
break;
case HPI_CONTROL_LEVEL:
if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
phr->u.c.an_log_value[0] = pC->u.l.an_log[0];
phr->u.c.an_log_value[1] = pC->u.l.an_log[1];
} else
found = 0;
break;
case HPI_CONTROL_TUNER:
{
struct hpi_control_cache_single *pCT =
(struct hpi_control_cache_single *)pI;
if (phm->u.c.attribute == HPI_TUNER_FREQ)
phr->u.c.param1 = pCT->u.t.freq_ink_hz;
else if (phm->u.c.attribute == HPI_TUNER_BAND)
phr->u.c.param1 = pCT->u.t.band;
else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
&& (phm->u.c.param1 ==
HPI_TUNER_LEVEL_AVERAGE))
phr->u.c.param1 = pCT->u.t.level;
else
found = 0;
}
break;
case HPI_CONTROL_AESEBU_RECEIVER:
if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
phr->u.c.param1 = pC->u.aes3rx.error_status;
else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
phr->u.c.param1 = pC->u.aes3rx.source;
else
found = 0;
break;
case HPI_CONTROL_AESEBU_TRANSMITTER:
if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
phr->u.c.param1 = pC->u.aes3tx.format;
else
found = 0;
break;
case HPI_CONTROL_TONEDETECTOR:
if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
phr->u.c.param1 = pC->u.tone.state;
else
found = 0;
break;
case HPI_CONTROL_SILENCEDETECTOR:
if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
phr->u.c.param1 = pC->u.silence.state;
phr->u.c.param2 = pC->u.silence.count;
} else
found = 0;
break;
case HPI_CONTROL_MICROPHONE:
if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
phr->u.c.param1 = pC->u.phantom_power.state;
else
found = 0;
break;
case HPI_CONTROL_SAMPLECLOCK:
if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
phr->u.c.param1 = pC->u.clk.source;
else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
if (pC->u.clk.source_index ==
HPI_ERROR_ILLEGAL_CACHE_VALUE) {
phr->u.c.param1 = 0;
phr->error = HPI_ERROR_INVALID_OPERATION;
} else
phr->u.c.param1 = pC->u.clk.source_index;
} else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
phr->u.c.param1 = pC->u.clk.sample_rate;
else
found = 0;
break;
case HPI_CONTROL_PAD:
if (!(p_pad->field_valid_flags & (1 <<
HPI_CTL_ATTR_INDEX(phm->u.c.
attribute)))) {
phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
break;
}
if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
phr->u.c.param1 = p_pad->pI;
else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
phr->u.c.param1 = p_pad->pTY;
else {
unsigned int index =
HPI_CTL_ATTR_INDEX(phm->u.c.attribute) - 1;
unsigned int offset = phm->u.c.param1;
unsigned int pad_string_len, field_size;
char *pad_string;
unsigned int tocopy;
HPI_DEBUG_LOG(VERBOSE, "PADS HPI_PADS_ %d\n",
phm->u.c.attribute);
if (index > ARRAY_SIZE(pad_desc) - 1) {
phr->error =
HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
break;
}
pad_string = ((char *)p_pad) + pad_desc[index].offset;
field_size = pad_desc[index].field_size;
/* Ensure null terminator */
pad_string[field_size - 1] = 0;
pad_string_len = strlen(pad_string) + 1;
if (offset > pad_string_len) {
phr->error = HPI_ERROR_INVALID_CONTROL_VALUE;
break;
}
tocopy = pad_string_len - offset;
if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
tocopy = sizeof(phr->u.cu.chars8.sz_data);
HPI_DEBUG_LOG(VERBOSE,
"PADS memcpy(%d), offset %d \n", tocopy,
offset);
memcpy(phr->u.cu.chars8.sz_data, &pad_string[offset],
tocopy);
phr->u.cu.chars8.remaining_chars =
pad_string_len - offset - tocopy;
}
break;
default:
found = 0;
break;
}
if (found)
HPI_DEBUG_LOG(VERBOSE,
"cached adap %d, ctl %d, type %d, attr %d\n",
phm->adapter_index, pI->control_index,
pI->control_type, phm->u.c.attribute);
else
HPI_DEBUG_LOG(VERBOSE,
"uncached adap %d, ctl %d, ctl type %d\n",
phm->adapter_index, pI->control_index,
pI->control_type);
if (found)
phr->size =
sizeof(struct hpi_response_header) +
sizeof(struct hpi_control_res);
return found;
}
/** Updates the cache with Set values.
Only update if no error.
Volume and Level return the limited values in the response, so use these
Multiplexer does so use sent values
*/
void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
struct hpi_message *phm, struct hpi_response *phr)
{
u16 control_index;
struct hpi_control_cache_single *pC;
struct hpi_control_cache_info *pI;
if (!find_control(phm, p_cache, &pI, &control_index))
return;
/* pC is the default cached control strucure.
May be cast to something else in the following switch statement.
*/
pC = (struct hpi_control_cache_single *)pI;
switch (pI->control_type) {
case HPI_CONTROL_VOLUME:
if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
pC->u.v.an_log[0] = phr->u.c.an_log_value[0];
pC->u.v.an_log[1] = phr->u.c.an_log_value[1];
}
break;
case HPI_CONTROL_MULTIPLEXER:
/* mux does not return its setting on Set command. */
if (phr->error)
return;
if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
pC->u.x.source_node_type = (u16)phm->u.c.param1;
pC->u.x.source_node_index = (u16)phm->u.c.param2;
}
break;
case HPI_CONTROL_CHANNEL_MODE:
/* mode does not return its setting on Set command. */
if (phr->error)
return;
if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
pC->u.m.mode = (u16)phm->u.c.param1;
break;
case HPI_CONTROL_LEVEL:
if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
pC->u.v.an_log[0] = phr->u.c.an_log_value[0];
pC->u.v.an_log[1] = phr->u.c.an_log_value[1];
}
break;
case HPI_CONTROL_MICROPHONE:
if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
pC->u.phantom_power.state = (u16)phm->u.c.param1;
break;
case HPI_CONTROL_AESEBU_TRANSMITTER:
if (phr->error)
return;
if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
pC->u.aes3tx.format = phm->u.c.param1;
break;
case HPI_CONTROL_AESEBU_RECEIVER:
if (phr->error)
return;
if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
pC->u.aes3rx.source = phm->u.c.param1;
break;
case HPI_CONTROL_SAMPLECLOCK:
if (phr->error)
return;
if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
pC->u.clk.source = (u16)phm->u.c.param1;
else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
pC->u.clk.source_index = (u16)phm->u.c.param1;
else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
pC->u.clk.sample_rate = phm->u.c.param1;
break;
default:
break;
}
}
struct hpi_control_cache *hpi_alloc_control_cache(const u32
number_of_controls, const u32 size_in_bytes,
struct hpi_control_cache_info *pDSP_control_buffer)
{
struct hpi_control_cache *p_cache =
kmalloc(sizeof(*p_cache), GFP_KERNEL);
p_cache->cache_size_in_bytes = size_in_bytes;
p_cache->control_count = number_of_controls;
p_cache->p_cache =
(struct hpi_control_cache_single *)pDSP_control_buffer;
p_cache->init = 0;
p_cache->p_info =
kmalloc(sizeof(*p_cache->p_info) * p_cache->control_count,
GFP_KERNEL);
return p_cache;
}
void hpi_free_control_cache(struct hpi_control_cache *p_cache)
{
if ((p_cache->init) && (p_cache->p_info)) {
kfree(p_cache->p_info);
p_cache->p_info = NULL;
p_cache->init = 0;
kfree(p_cache);
}
}
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
{
switch (phm->function) {
case HPI_SUBSYS_OPEN:
case HPI_SUBSYS_CLOSE:
case HPI_SUBSYS_DRIVER_UNLOAD:
phr->error = 0;
break;
case HPI_SUBSYS_DRIVER_LOAD:
wipe_adapter_list();
hpios_alistlock_init(&adapters);
phr->error = 0;
break;
case HPI_SUBSYS_GET_INFO:
subsys_get_adapters(phr);
break;
case HPI_SUBSYS_CREATE_ADAPTER:
case HPI_SUBSYS_DELETE_ADAPTER:
phr->error = 0;
break;
default:
phr->error = HPI_ERROR_INVALID_FUNC;
break;
}
}
void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
{
switch (phm->type) {
case HPI_TYPE_MESSAGE:
switch (phm->object) {
case HPI_OBJ_SUBSYSTEM:
subsys_message(phm, phr);
break;
}
break;
default:
phr->error = HPI_ERROR_INVALID_TYPE;
break;
}
}

64
sound/pci/asihpi/hpicmn.h Normal file
View File

@ -0,0 +1,64 @@
/**
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
struct hpi_adapter_obj {
struct hpi_pci pci; /* PCI info - bus#,dev#,address etc */
u16 adapter_type; /* ASI6701 etc */
u16 index; /* */
u16 open; /* =1 when adapter open */
u16 mixer_open;
struct hpios_spinlock dsp_lock;
u16 dsp_crashed;
u16 has_control_cache;
void *priv;
};
struct hpi_control_cache {
u32 init; /**< indicates whether the
structures are initialized */
u32 control_count;
u32 cache_size_in_bytes;
struct hpi_control_cache_info
**p_info; /**< pointer to allocated memory of
lookup pointers. */
struct hpi_control_cache_single
*p_cache; /**< pointer to DSP's control cache. */
};
struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index);
u16 hpi_add_adapter(struct hpi_adapter_obj *pao);
void hpi_delete_adapter(struct hpi_adapter_obj *pao);
short hpi_check_control_cache(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
struct hpi_control_cache *hpi_alloc_control_cache(const u32
number_of_controls, const u32 size_in_bytes,
struct hpi_control_cache_info
*pDSP_control_buffer);
void hpi_free_control_cache(struct hpi_control_cache *p_cache);
void hpi_sync_control_cache(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache,
struct hpi_message *phm, void **p, unsigned int *pN);

225
sound/pci/asihpi/hpidebug.c Normal file
View File

@ -0,0 +1,225 @@
/************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Debug macro translation.
************************************************************************/
#include "hpi_internal.h"
#include "hpidebug.h"
/* Debug level; 0 quiet; 1 informative, 2 debug, 3 verbose debug. */
int hpi_debug_level = HPI_DEBUG_LEVEL_DEFAULT;
void hpi_debug_init(void)
{
printk(KERN_INFO "debug start\n");
}
int hpi_debug_level_set(int level)
{
int old_level;
old_level = hpi_debug_level;
hpi_debug_level = level;
return old_level;
}
int hpi_debug_level_get(void)
{
return hpi_debug_level;
}
#ifdef HPIOS_DEBUG_PRINT
/* implies OS has no printf-like function */
#include <stdarg.h>
void hpi_debug_printf(char *fmt, ...)
{
va_list arglist;
char buffer[128];
va_start(arglist, fmt);
if (buffer[0])
HPIOS_DEBUG_PRINT(buffer);
va_end(arglist);
}
#endif
struct treenode {
void *array;
unsigned int num_elements;
};
#define make_treenode_from_array(nodename, array) \
static void *tmp_strarray_##nodename[] = array; \
static struct treenode nodename = { \
&tmp_strarray_##nodename, \
ARRAY_SIZE(tmp_strarray_##nodename) \
};
#define get_treenode_elem(node_ptr, idx, type) \
(&(*((type *)(node_ptr)->array)[idx]))
make_treenode_from_array(hpi_control_type_strings, HPI_CONTROL_TYPE_STRINGS)
make_treenode_from_array(hpi_subsys_strings, HPI_SUBSYS_STRINGS)
make_treenode_from_array(hpi_adapter_strings, HPI_ADAPTER_STRINGS)
make_treenode_from_array(hpi_istream_strings, HPI_ISTREAM_STRINGS)
make_treenode_from_array(hpi_ostream_strings, HPI_OSTREAM_STRINGS)
make_treenode_from_array(hpi_mixer_strings, HPI_MIXER_STRINGS)
make_treenode_from_array(hpi_node_strings,
{
"NODE is invalid object"})
make_treenode_from_array(hpi_control_strings, HPI_CONTROL_STRINGS)
make_treenode_from_array(hpi_nvmemory_strings, HPI_OBJ_STRINGS)
make_treenode_from_array(hpi_digitalio_strings, HPI_DIGITALIO_STRINGS)
make_treenode_from_array(hpi_watchdog_strings, HPI_WATCHDOG_STRINGS)
make_treenode_from_array(hpi_clock_strings, HPI_CLOCK_STRINGS)
make_treenode_from_array(hpi_profile_strings, HPI_PROFILE_STRINGS)
make_treenode_from_array(hpi_asyncevent_strings, HPI_ASYNCEVENT_STRINGS)
#define HPI_FUNCTION_STRINGS \
{ \
&hpi_subsys_strings,\
&hpi_adapter_strings,\
&hpi_ostream_strings,\
&hpi_istream_strings,\
&hpi_mixer_strings,\
&hpi_node_strings,\
&hpi_control_strings,\
&hpi_nvmemory_strings,\
&hpi_digitalio_strings,\
&hpi_watchdog_strings,\
&hpi_clock_strings,\
&hpi_profile_strings,\
&hpi_control_strings, \
&hpi_asyncevent_strings \
};
make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS)
compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match);
static char *hpi_function_string(unsigned int function)
{
unsigned int object;
struct treenode *tmp;
object = function / HPI_OBJ_FUNCTION_SPACING;
function = function - object * HPI_OBJ_FUNCTION_SPACING;
if (object == 0 || object == HPI_OBJ_NODE
|| object > hpi_function_strings.num_elements)
return "invalid object";
tmp = get_treenode_elem(&hpi_function_strings, object - 1,
struct treenode *);
if (function == 0 || function > tmp->num_elements)
return "invalid function";
return get_treenode_elem(tmp, function - 1, char *);
}
void hpi_debug_message(struct hpi_message *phm, char *sz_fileline)
{
if (phm) {
if ((phm->object <= HPI_OBJ_MAXINDEX) && phm->object) {
u16 index = 0;
u16 attrib = 0;
int is_control = 0;
index = phm->obj_index;
switch (phm->object) {
case HPI_OBJ_ADAPTER:
case HPI_OBJ_PROFILE:
break;
case HPI_OBJ_MIXER:
if (phm->function ==
HPI_MIXER_GET_CONTROL_BY_INDEX)
index = phm->u.m.control_index;
break;
case HPI_OBJ_OSTREAM:
case HPI_OBJ_ISTREAM:
break;
case HPI_OBJ_CONTROLEX:
case HPI_OBJ_CONTROL:
if (phm->version == 1)
attrib = HPI_CTL_ATTR(UNIVERSAL, 1);
else
attrib = phm->u.c.attribute;
is_control = 1;
break;
default:
break;
}
if (is_control && (attrib & 0xFF00)) {
int control_type = (attrib & 0xFF00) >> 8;
int attr_index = HPI_CTL_ATTR_INDEX(attrib);
/* note the KERN facility level
is in szFileline already */
printk("%s adapter %d %s "
"ctrl_index x%04x %s %d\n",
sz_fileline, phm->adapter_index,
hpi_function_string(phm->function),
index,
get_treenode_elem
(&hpi_control_type_strings,
control_type, char *),
attr_index);
} else
printk("%s adapter %d %s "
"idx x%04x attr x%04x \n",
sz_fileline, phm->adapter_index,
hpi_function_string(phm->function),
index, attrib);
} else {
printk("adap=%d, invalid obj=%d, func=0x%x\n",
phm->adapter_index, phm->object,
phm->function);
}
} else
printk(KERN_ERR
"NULL message pointer to hpi_debug_message!\n");
}
void hpi_debug_data(u16 *pdata, u32 len)
{
u32 i;
int j;
int k;
int lines;
int cols = 8;
lines = (len + cols - 1) / cols;
if (lines > 8)
lines = 8;
for (i = 0, j = 0; j < lines; j++) {
printk(KERN_DEBUG "%p:", (pdata + i));
for (k = 0; k < cols && i < len; i++, k++)
printk("%s%04x", k == 0 ? "" : " ", pdata[i]);
printk("\n");
}
}

385
sound/pci/asihpi/hpidebug.h Normal file
View File

@ -0,0 +1,385 @@
/*****************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Debug macros.
*****************************************************************************/
#ifndef _HPIDEBUG_H
#define _HPIDEBUG_H
#include "hpi_internal.h"
/* Define debugging levels. */
enum { HPI_DEBUG_LEVEL_ERROR = 0, /* always log errors */
HPI_DEBUG_LEVEL_WARNING = 1,
HPI_DEBUG_LEVEL_NOTICE = 2,
HPI_DEBUG_LEVEL_INFO = 3,
HPI_DEBUG_LEVEL_DEBUG = 4,
HPI_DEBUG_LEVEL_VERBOSE = 5 /* same printk level as DEBUG */
};
#define HPI_DEBUG_LEVEL_DEFAULT HPI_DEBUG_LEVEL_NOTICE
/* an OS can define an extra flag string that is appended to
the start of each message, eg see hpios_linux.h */
#ifdef SOURCEFILE_NAME
#define FILE_LINE SOURCEFILE_NAME ":" __stringify(__LINE__) " "
#else
#define FILE_LINE __FILE__ ":" __stringify(__LINE__) " "
#endif
#if defined(HPI_DEBUG) && defined(_WINDOWS)
#define HPI_DEBUGBREAK() debug_break()
#else
#define HPI_DEBUGBREAK()
#endif
#define HPI_DEBUG_ASSERT(expression) \
do { \
if (!(expression)) {\
printk(KERN_ERR FILE_LINE\
"ASSERT " __stringify(expression));\
HPI_DEBUGBREAK();\
} \
} while (0)
#define HPI_DEBUG_LOG(level, ...) \
do { \
if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \
printk(HPI_DEBUG_FLAG_##level \
FILE_LINE __VA_ARGS__); \
} \
} while (0)
void hpi_debug_init(void);
int hpi_debug_level_set(int level);
int hpi_debug_level_get(void);
/* needed by Linux driver for dynamic debug level changes */
extern int hpi_debug_level;
void hpi_debug_message(struct hpi_message *phm, char *sz_fileline);
void hpi_debug_data(u16 *pdata, u32 len);
#define HPI_DEBUG_DATA(pdata, len) \
do { \
if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) \
hpi_debug_data(pdata, len); \
} while (0)
#define HPI_DEBUG_MESSAGE(level, phm) \
do { \
if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \
hpi_debug_message(phm,HPI_DEBUG_FLAG_##level \
FILE_LINE __stringify(level));\
} \
} while (0)
#define HPI_DEBUG_RESPONSE(phr) \
do { \
if ((hpi_debug_level >= HPI_DEBUG_LEVEL_DEBUG) && (phr->error))\
HPI_DEBUG_LOG(ERROR, \
"HPI response - error# %d\n", \
phr->error); \
else if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) \
HPI_DEBUG_LOG(VERBOSE, "HPI response OK\n");\
} while (0)
#ifndef compile_time_assert
#define compile_time_assert(cond, msg) \
typedef char msg[(cond) ? 1 : -1]
#endif
/* check that size is exactly some number */
#define function_count_check(sym, size) \
compile_time_assert((sym##_FUNCTION_COUNT) == (size),\
strings_match_defs_##sym)
/* These strings should be generated using a macro which defines
the corresponding symbol values. */
#define HPI_OBJ_STRINGS \
{ \
"HPI_OBJ_SUBSYSTEM", \
"HPI_OBJ_ADAPTER", \
"HPI_OBJ_OSTREAM", \
"HPI_OBJ_ISTREAM", \
"HPI_OBJ_MIXER", \
"HPI_OBJ_NODE", \
"HPI_OBJ_CONTROL", \
"HPI_OBJ_NVMEMORY", \
"HPI_OBJ_DIGITALIO", \
"HPI_OBJ_WATCHDOG", \
"HPI_OBJ_CLOCK", \
"HPI_OBJ_PROFILE", \
"HPI_OBJ_CONTROLEX" \
}
#define HPI_SUBSYS_STRINGS \
{ \
"HPI_SUBSYS_OPEN", \
"HPI_SUBSYS_GET_VERSION", \
"HPI_SUBSYS_GET_INFO", \
"HPI_SUBSYS_FIND_ADAPTERS", \
"HPI_SUBSYS_CREATE_ADAPTER",\
"HPI_SUBSYS_CLOSE", \
"HPI_SUBSYS_DELETE_ADAPTER", \
"HPI_SUBSYS_DRIVER_LOAD", \
"HPI_SUBSYS_DRIVER_UNLOAD", \
"HPI_SUBSYS_READ_PORT_8", \
"HPI_SUBSYS_WRITE_PORT_8", \
"HPI_SUBSYS_GET_NUM_ADAPTERS",\
"HPI_SUBSYS_GET_ADAPTER", \
"HPI_SUBSYS_SET_NETWORK_INTERFACE"\
}
function_count_check(HPI_SUBSYS, 14);
#define HPI_ADAPTER_STRINGS \
{ \
"HPI_ADAPTER_OPEN", \
"HPI_ADAPTER_CLOSE", \
"HPI_ADAPTER_GET_INFO", \
"HPI_ADAPTER_GET_ASSERT", \
"HPI_ADAPTER_TEST_ASSERT", \
"HPI_ADAPTER_SET_MODE", \
"HPI_ADAPTER_GET_MODE", \
"HPI_ADAPTER_ENABLE_CAPABILITY",\
"HPI_ADAPTER_SELFTEST", \
"HPI_ADAPTER_FIND_OBJECT", \
"HPI_ADAPTER_QUERY_FLASH", \
"HPI_ADAPTER_START_FLASH", \
"HPI_ADAPTER_PROGRAM_FLASH", \
"HPI_ADAPTER_SET_PROPERTY", \
"HPI_ADAPTER_GET_PROPERTY", \
"HPI_ADAPTER_ENUM_PROPERTY", \
"HPI_ADAPTER_MODULE_INFO", \
"HPI_ADAPTER_DEBUG_READ" \
}
function_count_check(HPI_ADAPTER, 18);
#define HPI_OSTREAM_STRINGS \
{ \
"HPI_OSTREAM_OPEN", \
"HPI_OSTREAM_CLOSE", \
"HPI_OSTREAM_WRITE", \
"HPI_OSTREAM_START", \
"HPI_OSTREAM_STOP", \
"HPI_OSTREAM_RESET", \
"HPI_OSTREAM_GET_INFO", \
"HPI_OSTREAM_QUERY_FORMAT", \
"HPI_OSTREAM_DATA", \
"HPI_OSTREAM_SET_VELOCITY", \
"HPI_OSTREAM_SET_PUNCHINOUT", \
"HPI_OSTREAM_SINEGEN", \
"HPI_OSTREAM_ANC_RESET", \
"HPI_OSTREAM_ANC_GET_INFO", \
"HPI_OSTREAM_ANC_READ", \
"HPI_OSTREAM_SET_TIMESCALE",\
"HPI_OSTREAM_SET_FORMAT", \
"HPI_OSTREAM_HOSTBUFFER_ALLOC", \
"HPI_OSTREAM_HOSTBUFFER_FREE", \
"HPI_OSTREAM_GROUP_ADD",\
"HPI_OSTREAM_GROUP_GETMAP", \
"HPI_OSTREAM_GROUP_RESET", \
"HPI_OSTREAM_HOSTBUFFER_GET_INFO", \
"HPI_OSTREAM_WAIT_START", \
}
function_count_check(HPI_OSTREAM, 24);
#define HPI_ISTREAM_STRINGS \
{ \
"HPI_ISTREAM_OPEN", \
"HPI_ISTREAM_CLOSE", \
"HPI_ISTREAM_SET_FORMAT", \
"HPI_ISTREAM_READ", \
"HPI_ISTREAM_START", \
"HPI_ISTREAM_STOP", \
"HPI_ISTREAM_RESET", \
"HPI_ISTREAM_GET_INFO", \
"HPI_ISTREAM_QUERY_FORMAT", \
"HPI_ISTREAM_ANC_RESET", \
"HPI_ISTREAM_ANC_GET_INFO", \
"HPI_ISTREAM_ANC_WRITE", \
"HPI_ISTREAM_HOSTBUFFER_ALLOC",\
"HPI_ISTREAM_HOSTBUFFER_FREE", \
"HPI_ISTREAM_GROUP_ADD", \
"HPI_ISTREAM_GROUP_GETMAP", \
"HPI_ISTREAM_GROUP_RESET", \
"HPI_ISTREAM_HOSTBUFFER_GET_INFO", \
"HPI_ISTREAM_WAIT_START", \
}
function_count_check(HPI_ISTREAM, 19);
#define HPI_MIXER_STRINGS \
{ \
"HPI_MIXER_OPEN", \
"HPI_MIXER_CLOSE", \
"HPI_MIXER_GET_INFO", \
"HPI_MIXER_GET_NODE_INFO", \
"HPI_MIXER_GET_CONTROL", \
"HPI_MIXER_SET_CONNECTION", \
"HPI_MIXER_GET_CONNECTIONS", \
"HPI_MIXER_GET_CONTROL_BY_INDEX", \
"HPI_MIXER_GET_CONTROL_ARRAY_BY_INDEX", \
"HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES", \
"HPI_MIXER_STORE", \
}
function_count_check(HPI_MIXER, 11);
#define HPI_CONTROL_STRINGS \
{ \
"HPI_CONTROL_GET_INFO", \
"HPI_CONTROL_GET_STATE", \
"HPI_CONTROL_SET_STATE" \
}
function_count_check(HPI_CONTROL, 3);
#define HPI_NVMEMORY_STRINGS \
{ \
"HPI_NVMEMORY_OPEN", \
"HPI_NVMEMORY_READ_BYTE", \
"HPI_NVMEMORY_WRITE_BYTE" \
}
function_count_check(HPI_NVMEMORY, 3);
#define HPI_DIGITALIO_STRINGS \
{ \
"HPI_GPIO_OPEN", \
"HPI_GPIO_READ_BIT", \
"HPI_GPIO_WRITE_BIT", \
"HPI_GPIO_READ_ALL", \
"HPI_GPIO_WRITE_STATUS"\
}
function_count_check(HPI_GPIO, 5);
#define HPI_WATCHDOG_STRINGS \
{ \
"HPI_WATCHDOG_OPEN", \
"HPI_WATCHDOG_SET_TIME", \
"HPI_WATCHDOG_PING" \
}
#define HPI_CLOCK_STRINGS \
{ \
"HPI_CLOCK_OPEN", \
"HPI_CLOCK_SET_TIME", \
"HPI_CLOCK_GET_TIME" \
}
#define HPI_PROFILE_STRINGS \
{ \
"HPI_PROFILE_OPEN_ALL", \
"HPI_PROFILE_START_ALL", \
"HPI_PROFILE_STOP_ALL", \
"HPI_PROFILE_GET", \
"HPI_PROFILE_GET_IDLECOUNT", \
"HPI_PROFILE_GET_NAME", \
"HPI_PROFILE_GET_UTILIZATION" \
}
function_count_check(HPI_PROFILE, 7);
#define HPI_ASYNCEVENT_STRINGS \
{ \
"HPI_ASYNCEVENT_OPEN",\
"HPI_ASYNCEVENT_CLOSE ",\
"HPI_ASYNCEVENT_WAIT",\
"HPI_ASYNCEVENT_GETCOUNT",\
"HPI_ASYNCEVENT_GET",\
"HPI_ASYNCEVENT_SENDEVENTS"\
}
function_count_check(HPI_ASYNCEVENT, 6);
#define HPI_CONTROL_TYPE_STRINGS \
{ \
"null control", \
"HPI_CONTROL_CONNECTION", \
"HPI_CONTROL_VOLUME", \
"HPI_CONTROL_METER", \
"HPI_CONTROL_MUTE", \
"HPI_CONTROL_MULTIPLEXER", \
"HPI_CONTROL_AESEBU_TRANSMITTER", \
"HPI_CONTROL_AESEBU_RECEIVER", \
"HPI_CONTROL_LEVEL", \
"HPI_CONTROL_TUNER", \
"HPI_CONTROL_ONOFFSWITCH", \
"HPI_CONTROL_VOX", \
"HPI_CONTROL_AES18_TRANSMITTER", \
"HPI_CONTROL_AES18_RECEIVER", \
"HPI_CONTROL_AES18_BLOCKGENERATOR", \
"HPI_CONTROL_CHANNEL_MODE", \
"HPI_CONTROL_BITSTREAM", \
"HPI_CONTROL_SAMPLECLOCK", \
"HPI_CONTROL_MICROPHONE", \
"HPI_CONTROL_PARAMETRIC_EQ", \
"HPI_CONTROL_COMPANDER", \
"HPI_CONTROL_COBRANET", \
"HPI_CONTROL_TONE_DETECT", \
"HPI_CONTROL_SILENCE_DETECT", \
"HPI_CONTROL_PAD", \
"HPI_CONTROL_SRC" ,\
"HPI_CONTROL_UNIVERSAL" \
}
compile_time_assert((HPI_CONTROL_LAST_INDEX + 1 == 27),
controltype_strings_match_defs);
#define HPI_SOURCENODE_STRINGS \
{ \
"no source", \
"HPI_SOURCENODE_OSTREAM", \
"HPI_SOURCENODE_LINEIN", \
"HPI_SOURCENODE_AESEBU_IN", \
"HPI_SOURCENODE_TUNER", \
"HPI_SOURCENODE_RF", \
"HPI_SOURCENODE_CLOCK_SOURCE", \
"HPI_SOURCENODE_RAW_BITSTREAM", \
"HPI_SOURCENODE_MICROPHONE", \
"HPI_SOURCENODE_COBRANET", \
"HPI_SOURCENODE_ANALOG", \
"HPI_SOURCENODE_ADAPTER" \
}
compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) ==
(12), sourcenode_strings_match_defs);
#define HPI_DESTNODE_STRINGS \
{ \
"no destination", \
"HPI_DESTNODE_ISTREAM", \
"HPI_DESTNODE_LINEOUT", \
"HPI_DESTNODE_AESEBU_OUT", \
"HPI_DESTNODE_RF", \
"HPI_DESTNODE_SPEAKER", \
"HPI_DESTNODE_COBRANET", \
"HPI_DESTNODE_ANALOG" \
}
compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_BASE + 1) == (8),
destnode_strings_match_defs);
#define HPI_CONTROL_CHANNEL_MODE_STRINGS \
{ \
"XXX HPI_CHANNEL_MODE_ERROR XXX", \
"HPI_CHANNEL_MODE_NORMAL", \
"HPI_CHANNEL_MODE_SWAP", \
"HPI_CHANNEL_MODE_LEFT_ONLY", \
"HPI_CHANNEL_MODE_RIGHT_ONLY" \
}
#endif /* _HPIDEBUG_H */

172
sound/pci/asihpi/hpidspcd.c Normal file
View File

@ -0,0 +1,172 @@
/***********************************************************************/
/*!
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\file
Functions for reading DSP code to load into DSP
(Linux only:) If DSPCODE_FIRMWARE_LOADER is defined, code is read using
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"
#include "hpidspcd.h"
#include "hpidebug.h"
/**
Header structure for binary dsp code file (see asidsp.doc)
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 {
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 + \
HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
/***********************************************************************/
#include "linux/pci.h"
/*-------------------------------------------------------------------*/
short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
u32 *pos_error_code)
{
const struct firmware *ps_firmware = ps_dsp_code->ps_firmware;
struct code_header header;
char fw_name[20];
int err;
sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
HPI_DEBUG_LOG(INFO, "requesting firmware for %s\n", fw_name);
err = request_firmware(&ps_firmware, fw_name,
&ps_dsp_code->ps_dev->dev);
if (err != 0) {
HPI_DEBUG_LOG(ERROR, "%d, request_firmware failed for %s\n",
err, fw_name);
goto error1;
}
if (ps_firmware->size < sizeof(header)) {
HPI_DEBUG_LOG(ERROR, "header size too small %s\n", fw_name);
goto error2;
}
memcpy(&header, ps_firmware->data, sizeof(header));
if (header.adapter != adapter) {
HPI_DEBUG_LOG(ERROR, "adapter type incorrect %4x != %4x\n",
header.adapter, adapter);
goto error2;
}
if (header.size != ps_firmware->size) {
HPI_DEBUG_LOG(ERROR, "code size wrong %d != %ld\n",
header.size, (unsigned long)ps_firmware->size);
goto error2;
}
if (header.version / 10000 != HPI_VER_DECIMAL / 10000) {
HPI_DEBUG_LOG(ERROR,
"firmware major version mismatch "
"DSP image %d != driver %d\n", header.version,
HPI_VER_DECIMAL);
goto error2;
}
if (header.version != HPI_VER_DECIMAL) {
HPI_DEBUG_LOG(WARNING,
"version mismatch DSP image %d != driver %d\n",
header.version, HPI_VER_DECIMAL);
/* goto error2; still allow driver to load */
}
HPI_DEBUG_LOG(INFO, "dsp code %s opened\n", fw_name);
ps_dsp_code->ps_firmware = ps_firmware;
ps_dsp_code->block_length = header.size / sizeof(u32);
ps_dsp_code->word_count = sizeof(header) / sizeof(u32);
ps_dsp_code->version = header.version;
ps_dsp_code->crc = header.crc;
return 0;
error2:
release_firmware(ps_firmware);
error1:
ps_dsp_code->ps_firmware = NULL;
ps_dsp_code->block_length = 0;
return HPI_ERROR_DSP_FILE_NOT_FOUND;
}
/*-------------------------------------------------------------------*/
void hpi_dsp_code_close(struct dsp_code *ps_dsp_code)
{
if (ps_dsp_code->ps_firmware != NULL) {
HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
release_firmware(ps_dsp_code->ps_firmware);
ps_dsp_code->ps_firmware = NULL;
}
}
/*-------------------------------------------------------------------*/
void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code)
{
/* Go back to start of data, after header */
ps_dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
}
/*-------------------------------------------------------------------*/
short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword)
{
if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length)
return (HPI_ERROR_DSP_FILE_FORMAT);
*pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code->
word_count];
ps_dsp_code->word_count++;
return 0;
}
/*-------------------------------------------------------------------*/
short hpi_dsp_code_read_block(size_t words_requested,
struct dsp_code *ps_dsp_code, u32 **ppblock)
{
if (ps_dsp_code->word_count + words_requested >
ps_dsp_code->block_length)
return HPI_ERROR_DSP_FILE_FORMAT;
*ppblock =
((u32 *)(ps_dsp_code->ps_firmware->data)) +
ps_dsp_code->word_count;
ps_dsp_code->word_count += words_requested;
return 0;
}

104
sound/pci/asihpi/hpidspcd.h Normal file
View File

@ -0,0 +1,104 @@
/***********************************************************************/
/**
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\file
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_
#define _HPIDSPCD_H_
#include "hpi_internal.h"
#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(push, 1)
#endif
/** Descriptor for dspcode from firmware loader */
struct dsp_code {
/** Firmware descriptor */
const struct firmware *ps_firmware;
struct pci_dev *ps_dev;
/** Expected number of words in the whole dsp code,INCL header */
long int block_length;
/** Number of words read so far */
long int word_count;
/** Version read from dsp code file */
u32 version;
/** CRC read from dsp code file */
u32 crc;
};
#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(pop)
#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
*/
short hpi_dsp_code_open(
/** Code identifier, usually adapter family */
u32 adapter,
/** Pointer to DSP code control structure */
struct dsp_code *ps_dsp_code,
/** Pointer to dword to receive OS specific error code */
u32 *pos_error_code);
/** Close the DSP code file */
void hpi_dsp_code_close(struct dsp_code *ps_dsp_code);
/** Rewind to the beginning of the DSP code file (for verify) */
void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code);
/** Read one word from the dsp code file
\return 0 for success, or error code if eof, or block length exceeded
*/
short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code,
/**< DSP code descriptor */
u32 *pword /**< where to store the read word */
);
/** Get a block of dsp code into an internal buffer, and provide a pointer to
that buffer. (If dsp code is already an array in memory, it is referenced,
not copied.)
\return Error if requested number of words are not available
*/
short hpi_dsp_code_read_block(size_t words_requested,
struct dsp_code *ps_dsp_code,
/* Pointer to store (Pointer to code buffer) */
u32 **ppblock);
#endif

3864
sound/pci/asihpi/hpifunc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
/******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Hardware Programming Interface (HPI) Utility functions.
(C) Copyright AudioScience Inc. 2007
*******************************************************************************/
#include "hpi_internal.h"
#include "hpimsginit.h"
/* The actual message size for each object type */
static u16 msg_size[HPI_OBJ_MAXINDEX + 1] = HPI_MESSAGE_SIZE_BY_OBJECT;
/* The actual response size for each object type */
static u16 res_size[HPI_OBJ_MAXINDEX + 1] = HPI_RESPONSE_SIZE_BY_OBJECT;
/* Flag to enable alternate message type for SSX2 bypass. */
static u16 gwSSX2_bypass;
/** \internal
* Used by ASIO driver to disable SSX2 for a single process
* \param phSubSys Pointer to HPI subsystem handle.
* \param wBypass New bypass setting 0 = off, nonzero = on
* \return Previous bypass setting.
*/
u16 hpi_subsys_ssx2_bypass(const struct hpi_hsubsys *ph_subsys, u16 bypass)
{
u16 old_value = gwSSX2_bypass;
gwSSX2_bypass = bypass;
return old_value;
}
/** \internal
* initialize the HPI message structure
*/
static void hpi_init_message(struct hpi_message *phm, u16 object,
u16 function)
{
memset(phm, 0, sizeof(*phm));
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX))
phm->size = msg_size[object];
else
phm->size = sizeof(*phm);
if (gwSSX2_bypass)
phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE;
else
phm->type = HPI_TYPE_MESSAGE;
phm->object = object;
phm->function = function;
phm->version = 0;
/* Expect adapter index to be set by caller */
}
/** \internal
* initialize the HPI response structure
*/
void hpi_init_response(struct hpi_response *phr, u16 object, u16 function,
u16 error)
{
memset(phr, 0, sizeof(*phr));
phr->type = HPI_TYPE_RESPONSE;
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX))
phr->size = res_size[object];
else
phr->size = sizeof(*phr);
phr->object = object;
phr->function = function;
phr->error = error;
phr->specific_error = 0;
phr->version = 0;
}
void hpi_init_message_response(struct hpi_message *phm,
struct hpi_response *phr, u16 object, u16 function)
{
hpi_init_message(phm, object, function);
/* default error return if the response is
not filled in by the callee */
hpi_init_response(phr, object, function,
HPI_ERROR_PROCESSING_MESSAGE);
}
static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size,
u16 object, u16 function)
{
memset(phm, 0, sizeof(*phm));
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) {
phm->size = size;
phm->type = HPI_TYPE_MESSAGE;
phm->object = object;
phm->function = function;
phm->version = 1;
/* Expect adapter index to be set by caller */
}
}
void hpi_init_responseV1(struct hpi_response_header *phr, u16 size,
u16 object, u16 function)
{
memset(phr, 0, sizeof(*phr));
phr->size = size;
phr->version = 1;
phr->type = HPI_TYPE_RESPONSE;
phr->error = HPI_ERROR_PROCESSING_MESSAGE;
}
void hpi_init_message_responseV1(struct hpi_message_header *phm, u16 msg_size,
struct hpi_response_header *phr, u16 res_size, u16 object,
u16 function)
{
hpi_init_messageV1(phm, msg_size, object, function);
hpi_init_responseV1(phr, res_size, object, function);
}

View File

@ -0,0 +1,40 @@
/******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Hardware Programming Interface (HPI) Utility functions
(C) Copyright AudioScience Inc. 2007
*******************************************************************************/
/* Initialise response headers, or msg/response pairs.
Note that it is valid to just init a response e.g. when a lower level is preparing
a response to a message.
However, when sending a message, a matching response buffer always must be prepared
*/
void hpi_init_response(struct hpi_response *phr, u16 object, u16 function,
u16 error);
void hpi_init_message_response(struct hpi_message *phm,
struct hpi_response *phr, u16 object, u16 function);
void hpi_init_responseV1(struct hpi_response_header *phr, u16 size,
u16 object, u16 function);
void hpi_init_message_responseV1(struct hpi_message_header *phm, u16 msg_size,
struct hpi_response_header *phr, u16 res_size, u16 object,
u16 function);

907
sound/pci/asihpi/hpimsgx.c Normal file
View File

@ -0,0 +1,907 @@
/******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Extended Message Function With Response Cacheing
(C) Copyright AudioScience Inc. 2002
*****************************************************************************/
#define SOURCEFILE_NAME "hpimsgx.c"
#include "hpi_internal.h"
#include "hpimsginit.h"
#include "hpimsgx.h"
#include "hpidebug.h"
static struct pci_device_id asihpi_pci_tbl[] = {
#include "hpipcida.h"
};
static struct hpios_spinlock msgx_lock;
static hpi_handler_func *hpi_entry_points[HPI_MAX_ADAPTERS];
static hpi_handler_func *hpi_lookup_entry_point_function(const struct hpi_pci
*pci_info)
{
int i;
for (i = 0; asihpi_pci_tbl[i].vendor != 0; i++) {
if (asihpi_pci_tbl[i].vendor != PCI_ANY_ID
&& asihpi_pci_tbl[i].vendor != pci_info->vendor_id)
continue;
if (asihpi_pci_tbl[i].device != PCI_ANY_ID
&& asihpi_pci_tbl[i].device != pci_info->device_id)
continue;
if (asihpi_pci_tbl[i].subvendor != PCI_ANY_ID
&& asihpi_pci_tbl[i].subvendor !=
pci_info->subsys_vendor_id)
continue;
if (asihpi_pci_tbl[i].subdevice != PCI_ANY_ID
&& asihpi_pci_tbl[i].subdevice !=
pci_info->subsys_device_id)
continue;
HPI_DEBUG_LOG(DEBUG, " %x,%lu\n", i,
asihpi_pci_tbl[i].driver_data);
return (hpi_handler_func *) asihpi_pci_tbl[i].driver_data;
}
return NULL;
}
static inline void hw_entry_point(struct hpi_message *phm,
struct hpi_response *phr)
{
hpi_handler_func *ep;
if (phm->adapter_index < HPI_MAX_ADAPTERS) {
ep = (hpi_handler_func *) hpi_entry_points[phm->
adapter_index];
if (ep) {
HPI_DEBUG_MESSAGE(DEBUG, phm);
ep(phm, phr);
HPI_DEBUG_RESPONSE(phr);
return;
}
}
hpi_init_response(phr, phm->object, phm->function,
HPI_ERROR_PROCESSING_MESSAGE);
}
static void adapter_open(struct hpi_message *phm, struct hpi_response *phr);
static void adapter_close(struct hpi_message *phm, struct hpi_response *phr);
static void mixer_open(struct hpi_message *phm, struct hpi_response *phr);
static void mixer_close(struct hpi_message *phm, struct hpi_response *phr);
static void outstream_open(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner);
static void outstream_close(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner);
static void instream_open(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner);
static void instream_close(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner);
static void HPIMSGX__reset(u16 adapter_index);
static u16 HPIMSGX__init(struct hpi_message *phm, struct hpi_response *phr);
static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner);
#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(push, 1)
#endif
struct hpi_subsys_response {
struct hpi_response_header h;
struct hpi_subsys_res s;
};
struct hpi_adapter_response {
struct hpi_response_header h;
struct hpi_adapter_res a;
};
struct hpi_mixer_response {
struct hpi_response_header h;
struct hpi_mixer_res m;
};
struct hpi_stream_response {
struct hpi_response_header h;
struct hpi_stream_res d;
};
struct adapter_info {
u16 type;
u16 num_instreams;
u16 num_outstreams;
};
struct asi_open_state {
int open_flag;
void *h_owner;
};
#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(pop)
#endif
/* Globals */
static struct hpi_adapter_response rESP_HPI_ADAPTER_OPEN[HPI_MAX_ADAPTERS];
static struct hpi_stream_response
rESP_HPI_OSTREAM_OPEN[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
static struct hpi_stream_response
rESP_HPI_ISTREAM_OPEN[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
static struct hpi_mixer_response rESP_HPI_MIXER_OPEN[HPI_MAX_ADAPTERS];
static struct hpi_subsys_response gRESP_HPI_SUBSYS_FIND_ADAPTERS;
static struct adapter_info aDAPTER_INFO[HPI_MAX_ADAPTERS];
/* use these to keep track of opens from user mode apps/DLLs */
static struct asi_open_state
outstream_user_open[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
static struct asi_open_state
instream_user_open[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
switch (phm->function) {
case HPI_SUBSYS_GET_VERSION:
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_GET_VERSION, 0);
phr->u.s.version = HPI_VER >> 8; /* return major.minor */
phr->u.s.data = HPI_VER; /* return major.minor.release */
break;
case HPI_SUBSYS_OPEN:
/*do not propagate the message down the chain */
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_OPEN, 0);
break;
case HPI_SUBSYS_CLOSE:
/*do not propagate the message down the chain */
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CLOSE,
0);
HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner);
break;
case HPI_SUBSYS_DRIVER_LOAD:
/* Initialize this module's internal state */
hpios_msgxlock_init(&msgx_lock);
memset(&hpi_entry_points, 0, sizeof(hpi_entry_points));
hpios_locked_mem_init();
/* Init subsys_findadapters response to no-adapters */
HPIMSGX__reset(HPIMSGX_ALLADAPTERS);
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DRIVER_LOAD, 0);
/* individual HPIs dont implement driver load */
HPI_COMMON(phm, phr);
break;
case HPI_SUBSYS_DRIVER_UNLOAD:
HPI_COMMON(phm, phr);
HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner);
hpios_locked_mem_free_all();
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DRIVER_UNLOAD, 0);
return;
case HPI_SUBSYS_GET_INFO:
HPI_COMMON(phm, phr);
break;
case HPI_SUBSYS_FIND_ADAPTERS:
memcpy(phr, &gRESP_HPI_SUBSYS_FIND_ADAPTERS,
sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
break;
case HPI_SUBSYS_GET_NUM_ADAPTERS:
memcpy(phr, &gRESP_HPI_SUBSYS_FIND_ADAPTERS,
sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
phr->function = HPI_SUBSYS_GET_NUM_ADAPTERS;
break;
case HPI_SUBSYS_GET_ADAPTER:
{
int count = phm->adapter_index;
int index = 0;
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_GET_ADAPTER, 0);
/* This is complicated by the fact that we want to
* "skip" 0's in the adapter list.
* First, make sure we are pointing to a
* non-zero adapter type.
*/
while (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
s.aw_adapter_list[index] == 0) {
index++;
if (index >= HPI_MAX_ADAPTERS)
break;
}
while (count) {
/* move on to the next adapter */
index++;
if (index >= HPI_MAX_ADAPTERS)
break;
while (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
s.aw_adapter_list[index] == 0) {
index++;
if (index >= HPI_MAX_ADAPTERS)
break;
}
count--;
}
if (index < HPI_MAX_ADAPTERS) {
phr->u.s.adapter_index = (u16)index;
phr->u.s.aw_adapter_list[0] =
gRESP_HPI_SUBSYS_FIND_ADAPTERS.
s.aw_adapter_list[index];
} else {
phr->u.s.adapter_index = 0;
phr->u.s.aw_adapter_list[0] = 0;
phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER;
}
break;
}
case HPI_SUBSYS_CREATE_ADAPTER:
HPIMSGX__init(phm, phr);
break;
case HPI_SUBSYS_DELETE_ADAPTER:
HPIMSGX__cleanup(phm->adapter_index, h_owner);
{
struct hpi_message hm;
struct hpi_response hr;
/* call to HPI_ADAPTER_CLOSE */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_CLOSE);
hm.adapter_index = phm->adapter_index;
hw_entry_point(&hm, &hr);
}
hw_entry_point(phm, phr);
gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.
aw_adapter_list[phm->adapter_index]
= 0;
hpi_entry_points[phm->adapter_index] = NULL;
break;
default:
hw_entry_point(phm, phr);
break;
}
}
static void adapter_message(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
switch (phm->function) {
case HPI_ADAPTER_OPEN:
adapter_open(phm, phr);
break;
case HPI_ADAPTER_CLOSE:
adapter_close(phm, phr);
break;
default:
hw_entry_point(phm, phr);
break;
}
}
static void mixer_message(struct hpi_message *phm, struct hpi_response *phr)
{
switch (phm->function) {
case HPI_MIXER_OPEN:
mixer_open(phm, phr);
break;
case HPI_MIXER_CLOSE:
mixer_close(phm, phr);
break;
default:
hw_entry_point(phm, phr);
break;
}
}
static void outstream_message(struct hpi_message *phm,
struct hpi_response *phr, void *h_owner)
{
if (phm->obj_index >= aDAPTER_INFO[phm->adapter_index].num_outstreams) {
hpi_init_response(phr, HPI_OBJ_OSTREAM, phm->function,
HPI_ERROR_INVALID_OBJ_INDEX);
return;
}
switch (phm->function) {
case HPI_OSTREAM_OPEN:
outstream_open(phm, phr, h_owner);
break;
case HPI_OSTREAM_CLOSE:
outstream_close(phm, phr, h_owner);
break;
default:
hw_entry_point(phm, phr);
break;
}
}
static void instream_message(struct hpi_message *phm,
struct hpi_response *phr, void *h_owner)
{
if (phm->obj_index >= aDAPTER_INFO[phm->adapter_index].num_instreams) {
hpi_init_response(phr, HPI_OBJ_ISTREAM, phm->function,
HPI_ERROR_INVALID_OBJ_INDEX);
return;
}
switch (phm->function) {
case HPI_ISTREAM_OPEN:
instream_open(phm, phr, h_owner);
break;
case HPI_ISTREAM_CLOSE:
instream_close(phm, phr, h_owner);
break;
default:
hw_entry_point(phm, phr);
break;
}
}
/* NOTE: HPI_Message() must be defined in the driver as a wrapper for
* HPI_MessageEx so that functions in hpifunc.c compile.
*/
void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
HPI_DEBUG_MESSAGE(DEBUG, phm);
if (phm->type != HPI_TYPE_MESSAGE) {
hpi_init_response(phr, phm->object, phm->function,
HPI_ERROR_INVALID_TYPE);
return;
}
if (phm->adapter_index >= HPI_MAX_ADAPTERS
&& phm->adapter_index != HPIMSGX_ALLADAPTERS) {
hpi_init_response(phr, phm->object, phm->function,
HPI_ERROR_BAD_ADAPTER_NUMBER);
return;
}
switch (phm->object) {
case HPI_OBJ_SUBSYSTEM:
subsys_message(phm, phr, h_owner);
break;
case HPI_OBJ_ADAPTER:
adapter_message(phm, phr, h_owner);
break;
case HPI_OBJ_MIXER:
mixer_message(phm, phr);
break;
case HPI_OBJ_OSTREAM:
outstream_message(phm, phr, h_owner);
break;
case HPI_OBJ_ISTREAM:
instream_message(phm, phr, h_owner);
break;
default:
hw_entry_point(phm, phr);
break;
}
HPI_DEBUG_RESPONSE(phr);
#if 1
if (phr->error >= HPI_ERROR_BACKEND_BASE) {
void *ep = NULL;
char *ep_name;
HPI_DEBUG_MESSAGE(ERROR, phm);
if (phm->adapter_index < HPI_MAX_ADAPTERS)
ep = hpi_entry_points[phm->adapter_index];
/* Don't need this? Have adapter index in debug info
Know at driver load time index->backend mapping */
if (ep == HPI_6000)
ep_name = "HPI_6000";
else if (ep == HPI_6205)
ep_name = "HPI_6205";
else
ep_name = "unknown";
HPI_DEBUG_LOG(ERROR, "HPI %s response - error# %d\n", ep_name,
phr->error);
if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE)
hpi_debug_data((u16 *)phm,
sizeof(*phm) / sizeof(u16));
}
#endif
}
static void adapter_open(struct hpi_message *phm, struct hpi_response *phr)
{
HPI_DEBUG_LOG(VERBOSE, "adapter_open\n");
memcpy(phr, &rESP_HPI_ADAPTER_OPEN[phm->adapter_index],
sizeof(rESP_HPI_ADAPTER_OPEN[0]));
}
static void adapter_close(struct hpi_message *phm, struct hpi_response *phr)
{
HPI_DEBUG_LOG(VERBOSE, "adapter_close\n");
hpi_init_response(phr, HPI_OBJ_ADAPTER, HPI_ADAPTER_CLOSE, 0);
}
static void mixer_open(struct hpi_message *phm, struct hpi_response *phr)
{
memcpy(phr, &rESP_HPI_MIXER_OPEN[phm->adapter_index],
sizeof(rESP_HPI_MIXER_OPEN[0]));
}
static void mixer_close(struct hpi_message *phm, struct hpi_response *phr)
{
hpi_init_response(phr, HPI_OBJ_MIXER, HPI_MIXER_CLOSE, 0);
}
static void instream_open(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_response(phr, HPI_OBJ_ISTREAM, HPI_ISTREAM_OPEN, 0);
hpios_msgxlock_lock(&msgx_lock);
if (instream_user_open[phm->adapter_index][phm->obj_index].open_flag)
phr->error = HPI_ERROR_OBJ_ALREADY_OPEN;
else if (rESP_HPI_ISTREAM_OPEN[phm->adapter_index]
[phm->obj_index].h.error)
memcpy(phr,
&rESP_HPI_ISTREAM_OPEN[phm->adapter_index][phm->
obj_index],
sizeof(rESP_HPI_ISTREAM_OPEN[0][0]));
else {
instream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 1;
hpios_msgxlock_un_lock(&msgx_lock);
/* issue a reset */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_RESET);
hm.adapter_index = phm->adapter_index;
hm.obj_index = phm->obj_index;
hw_entry_point(&hm, &hr);
hpios_msgxlock_lock(&msgx_lock);
if (hr.error) {
instream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 0;
phr->error = hr.error;
} else {
instream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 1;
instream_user_open[phm->adapter_index][phm->
obj_index].h_owner = h_owner;
memcpy(phr,
&rESP_HPI_ISTREAM_OPEN[phm->adapter_index]
[phm->obj_index],
sizeof(rESP_HPI_ISTREAM_OPEN[0][0]));
}
}
hpios_msgxlock_un_lock(&msgx_lock);
}
static void instream_close(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_response(phr, HPI_OBJ_ISTREAM, HPI_ISTREAM_CLOSE, 0);
hpios_msgxlock_lock(&msgx_lock);
if (h_owner ==
instream_user_open[phm->adapter_index][phm->
obj_index].h_owner) {
/* HPI_DEBUG_LOG(INFO,"closing adapter %d "
"instream %d owned by %p\n",
phm->wAdapterIndex, phm->wObjIndex, hOwner); */
instream_user_open[phm->adapter_index][phm->
obj_index].h_owner = NULL;
hpios_msgxlock_un_lock(&msgx_lock);
/* issue a reset */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_RESET);
hm.adapter_index = phm->adapter_index;
hm.obj_index = phm->obj_index;
hw_entry_point(&hm, &hr);
hpios_msgxlock_lock(&msgx_lock);
if (hr.error) {
instream_user_open[phm->adapter_index][phm->
obj_index].h_owner = h_owner;
phr->error = hr.error;
} else {
instream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 0;
instream_user_open[phm->adapter_index][phm->
obj_index].h_owner = NULL;
}
} else {
HPI_DEBUG_LOG(WARNING,
"%p trying to close %d instream %d owned by %p\n",
h_owner, phm->adapter_index, phm->obj_index,
instream_user_open[phm->adapter_index][phm->
obj_index].h_owner);
phr->error = HPI_ERROR_OBJ_NOT_OPEN;
}
hpios_msgxlock_un_lock(&msgx_lock);
}
static void outstream_open(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_response(phr, HPI_OBJ_OSTREAM, HPI_OSTREAM_OPEN, 0);
hpios_msgxlock_lock(&msgx_lock);
if (outstream_user_open[phm->adapter_index][phm->obj_index].open_flag)
phr->error = HPI_ERROR_OBJ_ALREADY_OPEN;
else if (rESP_HPI_OSTREAM_OPEN[phm->adapter_index]
[phm->obj_index].h.error)
memcpy(phr,
&rESP_HPI_OSTREAM_OPEN[phm->adapter_index][phm->
obj_index],
sizeof(rESP_HPI_OSTREAM_OPEN[0][0]));
else {
outstream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 1;
hpios_msgxlock_un_lock(&msgx_lock);
/* issue a reset */
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_RESET);
hm.adapter_index = phm->adapter_index;
hm.obj_index = phm->obj_index;
hw_entry_point(&hm, &hr);
hpios_msgxlock_lock(&msgx_lock);
if (hr.error) {
outstream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 0;
phr->error = hr.error;
} else {
outstream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 1;
outstream_user_open[phm->adapter_index][phm->
obj_index].h_owner = h_owner;
memcpy(phr,
&rESP_HPI_OSTREAM_OPEN[phm->adapter_index]
[phm->obj_index],
sizeof(rESP_HPI_OSTREAM_OPEN[0][0]));
}
}
hpios_msgxlock_un_lock(&msgx_lock);
}
static void outstream_close(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_response(phr, HPI_OBJ_OSTREAM, HPI_OSTREAM_CLOSE, 0);
hpios_msgxlock_lock(&msgx_lock);
if (h_owner ==
outstream_user_open[phm->adapter_index][phm->
obj_index].h_owner) {
/* HPI_DEBUG_LOG(INFO,"closing adapter %d "
"outstream %d owned by %p\n",
phm->wAdapterIndex, phm->wObjIndex, hOwner); */
outstream_user_open[phm->adapter_index][phm->
obj_index].h_owner = NULL;
hpios_msgxlock_un_lock(&msgx_lock);
/* issue a reset */
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_RESET);
hm.adapter_index = phm->adapter_index;
hm.obj_index = phm->obj_index;
hw_entry_point(&hm, &hr);
hpios_msgxlock_lock(&msgx_lock);
if (hr.error) {
outstream_user_open[phm->adapter_index][phm->
obj_index].h_owner = h_owner;
phr->error = hr.error;
} else {
outstream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 0;
outstream_user_open[phm->adapter_index][phm->
obj_index].h_owner = NULL;
}
} else {
HPI_DEBUG_LOG(WARNING,
"%p trying to close %d outstream %d owned by %p\n",
h_owner, phm->adapter_index, phm->obj_index,
outstream_user_open[phm->adapter_index][phm->
obj_index].h_owner);
phr->error = HPI_ERROR_OBJ_NOT_OPEN;
}
hpios_msgxlock_un_lock(&msgx_lock);
}
static u16 adapter_prepare(u16 adapter)
{
struct hpi_message hm;
struct hpi_response hr;
/* Open the adapter and streams */
u16 i;
/* call to HPI_ADAPTER_OPEN */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_OPEN);
hm.adapter_index = adapter;
hw_entry_point(&hm, &hr);
memcpy(&rESP_HPI_ADAPTER_OPEN[adapter], &hr,
sizeof(rESP_HPI_ADAPTER_OPEN[0]));
if (hr.error)
return hr.error;
/* call to HPI_ADAPTER_GET_INFO */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_GET_INFO);
hm.adapter_index = adapter;
hw_entry_point(&hm, &hr);
if (hr.error)
return hr.error;
aDAPTER_INFO[adapter].num_outstreams = hr.u.a.num_outstreams;
aDAPTER_INFO[adapter].num_instreams = hr.u.a.num_instreams;
aDAPTER_INFO[adapter].type = hr.u.a.adapter_type;
gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list[adapter] =
hr.u.a.adapter_type;
gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters++;
if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters > HPI_MAX_ADAPTERS)
gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters =
HPI_MAX_ADAPTERS;
/* call to HPI_OSTREAM_OPEN */
for (i = 0; i < aDAPTER_INFO[adapter].num_outstreams; i++) {
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_OPEN);
hm.adapter_index = adapter;
hm.obj_index = i;
hw_entry_point(&hm, &hr);
memcpy(&rESP_HPI_OSTREAM_OPEN[adapter][i], &hr,
sizeof(rESP_HPI_OSTREAM_OPEN[0][0]));
outstream_user_open[adapter][i].open_flag = 0;
outstream_user_open[adapter][i].h_owner = NULL;
}
/* call to HPI_ISTREAM_OPEN */
for (i = 0; i < aDAPTER_INFO[adapter].num_instreams; i++) {
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_OPEN);
hm.adapter_index = adapter;
hm.obj_index = i;
hw_entry_point(&hm, &hr);
memcpy(&rESP_HPI_ISTREAM_OPEN[adapter][i], &hr,
sizeof(rESP_HPI_ISTREAM_OPEN[0][0]));
instream_user_open[adapter][i].open_flag = 0;
instream_user_open[adapter][i].h_owner = NULL;
}
/* call to HPI_MIXER_OPEN */
hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_OPEN);
hm.adapter_index = adapter;
hw_entry_point(&hm, &hr);
memcpy(&rESP_HPI_MIXER_OPEN[adapter], &hr,
sizeof(rESP_HPI_MIXER_OPEN[0]));
return gRESP_HPI_SUBSYS_FIND_ADAPTERS.h.error;
}
static void HPIMSGX__reset(u16 adapter_index)
{
int i;
u16 adapter;
struct hpi_response hr;
if (adapter_index == HPIMSGX_ALLADAPTERS) {
/* reset all responses to contain errors */
hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_FIND_ADAPTERS, 0);
memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr,
sizeof(&gRESP_HPI_SUBSYS_FIND_ADAPTERS));
for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) {
hpi_init_response(&hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_OPEN, HPI_ERROR_BAD_ADAPTER);
memcpy(&rESP_HPI_ADAPTER_OPEN[adapter], &hr,
sizeof(rESP_HPI_ADAPTER_OPEN[adapter]));
hpi_init_response(&hr, HPI_OBJ_MIXER, HPI_MIXER_OPEN,
HPI_ERROR_INVALID_OBJ);
memcpy(&rESP_HPI_MIXER_OPEN[adapter], &hr,
sizeof(rESP_HPI_MIXER_OPEN[adapter]));
for (i = 0; i < HPI_MAX_STREAMS; i++) {
hpi_init_response(&hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_OPEN,
HPI_ERROR_INVALID_OBJ);
memcpy(&rESP_HPI_OSTREAM_OPEN[adapter][i],
&hr,
sizeof(rESP_HPI_OSTREAM_OPEN[adapter]
[i]));
hpi_init_response(&hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_OPEN,
HPI_ERROR_INVALID_OBJ);
memcpy(&rESP_HPI_ISTREAM_OPEN[adapter][i],
&hr,
sizeof(rESP_HPI_ISTREAM_OPEN[adapter]
[i]));
}
}
} else if (adapter_index < HPI_MAX_ADAPTERS) {
rESP_HPI_ADAPTER_OPEN[adapter_index].h.error =
HPI_ERROR_BAD_ADAPTER;
rESP_HPI_MIXER_OPEN[adapter_index].h.error =
HPI_ERROR_INVALID_OBJ;
for (i = 0; i < HPI_MAX_STREAMS; i++) {
rESP_HPI_OSTREAM_OPEN[adapter_index][i].h.error =
HPI_ERROR_INVALID_OBJ;
rESP_HPI_ISTREAM_OPEN[adapter_index][i].h.error =
HPI_ERROR_INVALID_OBJ;
}
if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
s.aw_adapter_list[adapter_index]) {
gRESP_HPI_SUBSYS_FIND_ADAPTERS.
s.aw_adapter_list[adapter_index] = 0;
gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters--;
}
}
}
static u16 HPIMSGX__init(struct hpi_message *phm,
/* HPI_SUBSYS_CREATE_ADAPTER structure with */
/* resource list or NULL=find all */
struct hpi_response *phr
/* response from HPI_ADAPTER_GET_INFO */
)
{
hpi_handler_func *entry_point_func;
struct hpi_response hr;
if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters >= HPI_MAX_ADAPTERS)
return HPI_ERROR_BAD_ADAPTER_NUMBER;
/* Init response here so we can pass in previous adapter list */
hpi_init_response(&hr, phm->object, phm->function,
HPI_ERROR_INVALID_OBJ);
memcpy(hr.u.s.aw_adapter_list,
gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list,
sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list));
entry_point_func =
hpi_lookup_entry_point_function(phm->u.s.resource.r.pci);
if (entry_point_func) {
HPI_DEBUG_MESSAGE(DEBUG, phm);
entry_point_func(phm, &hr);
} else {
phr->error = HPI_ERROR_PROCESSING_MESSAGE;
return phr->error;
}
if (hr.error == 0) {
/* the adapter was created succesfully
save the mapping for future use */
hpi_entry_points[hr.u.s.adapter_index] = entry_point_func;
/* prepare adapter (pre-open streams etc.) */
HPI_DEBUG_LOG(DEBUG,
"HPI_SUBSYS_CREATE_ADAPTER successful,"
" preparing adapter\n");
adapter_prepare(hr.u.s.adapter_index);
}
memcpy(phr, &hr, hr.size);
return phr->error;
}
static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner)
{
int i, adapter, adapter_limit;
if (!h_owner)
return;
if (adapter_index == HPIMSGX_ALLADAPTERS) {
adapter = 0;
adapter_limit = HPI_MAX_ADAPTERS;
} else {
adapter = adapter_index;
adapter_limit = adapter + 1;
}
for (; adapter < adapter_limit; adapter++) {
/* printk(KERN_INFO "Cleanup adapter #%d\n",wAdapter); */
for (i = 0; i < HPI_MAX_STREAMS; i++) {
if (h_owner ==
outstream_user_open[adapter][i].h_owner) {
struct hpi_message hm;
struct hpi_response hr;
HPI_DEBUG_LOG(DEBUG,
"close adapter %d ostream %d\n",
adapter, i);
hpi_init_message_response(&hm, &hr,
HPI_OBJ_OSTREAM, HPI_OSTREAM_RESET);
hm.adapter_index = (u16)adapter;
hm.obj_index = (u16)i;
hw_entry_point(&hm, &hr);
hm.function = HPI_OSTREAM_HOSTBUFFER_FREE;
hw_entry_point(&hm, &hr);
hm.function = HPI_OSTREAM_GROUP_RESET;
hw_entry_point(&hm, &hr);
outstream_user_open[adapter][i].open_flag = 0;
outstream_user_open[adapter][i].h_owner =
NULL;
}
if (h_owner == instream_user_open[adapter][i].h_owner) {
struct hpi_message hm;
struct hpi_response hr;
HPI_DEBUG_LOG(DEBUG,
"close adapter %d istream %d\n",
adapter, i);
hpi_init_message_response(&hm, &hr,
HPI_OBJ_ISTREAM, HPI_ISTREAM_RESET);
hm.adapter_index = (u16)adapter;
hm.obj_index = (u16)i;
hw_entry_point(&hm, &hr);
hm.function = HPI_ISTREAM_HOSTBUFFER_FREE;
hw_entry_point(&hm, &hr);
hm.function = HPI_ISTREAM_GROUP_RESET;
hw_entry_point(&hm, &hr);
instream_user_open[adapter][i].open_flag = 0;
instream_user_open[adapter][i].h_owner = NULL;
}
}
}
}

View File

@ -0,0 +1,36 @@
/******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
HPI Extended Message Handler Functions
(C) Copyright AudioScience Inc. 1997-2003
******************************************************************************/
#ifndef _HPIMSGX_H_
#define _HPIMSGX_H_
#include "hpi_internal.h"
#define HPIMSGX_ALLADAPTERS (0xFFFF)
void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner);
#define HPI_MESSAGE_LOWER_LAYER hpi_send_recv_ex
#endif /* _HPIMSGX_H_ */

484
sound/pci/asihpi/hpioctl.c Normal file
View File

@ -0,0 +1,484 @@
/*******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Common Linux HPI ioctl and module probe/remove functions
*******************************************************************************/
#define SOURCEFILE_NAME "hpioctl.c"
#include "hpi_internal.h"
#include "hpimsginit.h"
#include "hpidebug.h"
#include "hpimsgx.h"
#include "hpioctl.h"
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
#include <linux/stringify.h>
#ifdef MODULE_FIRMWARE
MODULE_FIRMWARE("asihpi/dsp5000.bin");
MODULE_FIRMWARE("asihpi/dsp6200.bin");
MODULE_FIRMWARE("asihpi/dsp6205.bin");
MODULE_FIRMWARE("asihpi/dsp6400.bin");
MODULE_FIRMWARE("asihpi/dsp6600.bin");
MODULE_FIRMWARE("asihpi/dsp8700.bin");
MODULE_FIRMWARE("asihpi/dsp8900.bin");
#endif
static int prealloc_stream_buf;
module_param(prealloc_stream_buf, int, S_IRUGO);
MODULE_PARM_DESC(prealloc_stream_buf,
"preallocate size for per-adapter stream buffer");
/* Allow the debug level to be changed after module load.
E.g. echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel
*/
module_param(hpi_debug_level, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(hpi_debug_level, "debug verbosity 0..5");
/* List of adapters found */
static struct hpi_adapter adapters[HPI_MAX_ADAPTERS];
/* Wrapper function to HPI_Message to enable dumping of the
message and response types.
*/
static void hpi_send_recv_f(struct hpi_message *phm, struct hpi_response *phr,
struct file *file)
{
int adapter = phm->adapter_index;
if ((adapter >= HPI_MAX_ADAPTERS || adapter < 0)
&& (phm->object != HPI_OBJ_SUBSYSTEM))
phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
else
hpi_send_recv_ex(phm, phr, file);
}
/* This is called from hpifunc.c functions, called by ALSA
* (or other kernel process) In this case there is no file descriptor
* available for the message cache code
*/
void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr)
{
hpi_send_recv_f(phm, phr, HOWNER_KERNEL);
}
EXPORT_SYMBOL(hpi_send_recv);
/* for radio-asihpi */
int asihpi_hpi_release(struct file *file)
{
struct hpi_message hm;
struct hpi_response hr;
/* HPI_DEBUG_LOG(INFO,"hpi_release file %p, pid %d\n", file, current->pid); */
/* close the subsystem just in case the application forgot to. */
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_CLOSE);
hpi_send_recv_ex(&hm, &hr, file);
return 0;
}
long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct hpi_ioctl_linux __user *phpi_ioctl_data;
void __user *puhm;
void __user *puhr;
union hpi_message_buffer_v1 *hm;
union hpi_response_buffer_v1 *hr;
u16 res_max_size;
u32 uncopied_bytes;
struct hpi_adapter *pa = NULL;
int err = 0;
if (cmd != HPI_IOCTL_LINUX)
return -EINVAL;
hm = kmalloc(sizeof(*hm), GFP_KERNEL);
hr = kmalloc(sizeof(*hr), GFP_KERNEL);
if (!hm || !hr) {
err = -ENOMEM;
goto out;
}
phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg;
/* Read the message and response pointers from user space. */
get_user(puhm, &phpi_ioctl_data->phm);
get_user(puhr, &phpi_ioctl_data->phr);
/* Now read the message size and data from user space. */
get_user(hm->h.size, (u16 __user *)puhm);
if (hm->h.size > sizeof(*hm))
hm->h.size = sizeof(*hm);
/*printk(KERN_INFO "message size %d\n", hm->h.wSize); */
uncopied_bytes = copy_from_user(hm, puhm, hm->h.size);
if (uncopied_bytes) {
HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes);
err = -EFAULT;
goto out;
}
get_user(res_max_size, (u16 __user *)puhr);
/* printk(KERN_INFO "user response size %d\n", res_max_size); */
if (res_max_size < sizeof(struct hpi_response_header)) {
HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size);
err = -EFAULT;
goto out;
}
pa = &adapters[hm->h.adapter_index];
hr->h.size = 0;
if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
switch (hm->h.function) {
case HPI_SUBSYS_CREATE_ADAPTER:
case HPI_SUBSYS_DELETE_ADAPTER:
/* Application must not use these functions! */
hr->h.size = sizeof(hr->h);
hr->h.error = HPI_ERROR_INVALID_OPERATION;
hr->h.function = hm->h.function;
uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
if (uncopied_bytes)
err = -EFAULT;
else
err = 0;
goto out;
default:
hpi_send_recv_f(&hm->m0, &hr->r0, file);
}
} else {
u16 __user *ptr = NULL;
u32 size = 0;
/* -1=no data 0=read from user mem, 1=write to user mem */
int wrflag = -1;
u32 adapter = hm->h.adapter_index;
if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) {
hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
HPI_ADAPTER_OPEN,
HPI_ERROR_BAD_ADAPTER_NUMBER);
uncopied_bytes =
copy_to_user(puhr, hr, sizeof(hr->h));
if (uncopied_bytes)
err = -EFAULT;
else
err = 0;
goto out;
}
if (mutex_lock_interruptible(&adapters[adapter].mutex)) {
err = -EINTR;
goto out;
}
/* Dig out any pointers embedded in the message. */
switch (hm->h.function) {
case HPI_OSTREAM_WRITE:
case HPI_ISTREAM_READ:{
/* Yes, sparse, this is correct. */
ptr = (u16 __user *)hm->m0.u.d.u.data.pb_data;
size = hm->m0.u.d.u.data.data_size;
/* Allocate buffer according to application request.
?Is it better to alloc/free for the duration
of the transaction?
*/
if (pa->buffer_size < size) {
HPI_DEBUG_LOG(DEBUG,
"realloc adapter %d stream "
"buffer from %zd to %d\n",
hm->h.adapter_index,
pa->buffer_size, size);
if (pa->p_buffer) {
pa->buffer_size = 0;
vfree(pa->p_buffer);
}
pa->p_buffer = vmalloc(size);
if (pa->p_buffer)
pa->buffer_size = size;
else {
HPI_DEBUG_LOG(ERROR,
"HPI could not allocate "
"stream buffer size %d\n",
size);
mutex_unlock(&adapters
[adapter].mutex);
err = -EINVAL;
goto out;
}
}
hm->m0.u.d.u.data.pb_data = pa->p_buffer;
if (hm->h.function == HPI_ISTREAM_READ)
/* from card, WRITE to user mem */
wrflag = 1;
else
wrflag = 0;
break;
}
default:
size = 0;
break;
}
if (size && (wrflag == 0)) {
uncopied_bytes =
copy_from_user(pa->p_buffer, ptr, size);
if (uncopied_bytes)
HPI_DEBUG_LOG(WARNING,
"missed %d of %d "
"bytes from user\n", uncopied_bytes,
size);
}
hpi_send_recv_f(&hm->m0, &hr->r0, file);
if (size && (wrflag == 1)) {
uncopied_bytes =
copy_to_user(ptr, pa->p_buffer, size);
if (uncopied_bytes)
HPI_DEBUG_LOG(WARNING,
"missed %d of %d " "bytes to user\n",
uncopied_bytes, size);
}
mutex_unlock(&adapters[adapter].mutex);
}
/* on return response size must be set */
/*printk(KERN_INFO "response size %d\n", hr->h.wSize); */
if (!hr->h.size) {
HPI_DEBUG_LOG(ERROR, "response zero size\n");
err = -EFAULT;
goto out;
}
if (hr->h.size > res_max_size) {
HPI_DEBUG_LOG(ERROR, "response too big %d %d\n", hr->h.size,
res_max_size);
/*HPI_DEBUG_MESSAGE(ERROR, hm); */
err = -EFAULT;
goto out;
}
uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
if (uncopied_bytes) {
HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes);
err = -EFAULT;
goto out;
}
out:
kfree(hm);
kfree(hr);
return err;
}
int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
int err, idx, nm;
unsigned int memlen;
struct hpi_message hm;
struct hpi_response hr;
struct hpi_adapter adapter;
struct hpi_pci pci;
memset(&adapter, 0, sizeof(adapter));
printk(KERN_DEBUG "probe PCI device (%04x:%04x,%04x:%04x,%04x)\n",
pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor,
pci_dev->subsystem_device, pci_dev->devfn);
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_CREATE_ADAPTER);
hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER,
HPI_ERROR_PROCESSING_MESSAGE);
hm.adapter_index = -1; /* an invalid index */
/* fill in HPI_PCI information from kernel provided information */
adapter.pci = pci_dev;
nm = HPI_MAX_ADAPTER_MEM_SPACES;
for (idx = 0; idx < nm; idx++) {
HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n",
idx, pci_dev->resource[idx].name,
(unsigned long long)pci_resource_start(pci_dev, idx),
(unsigned long long)pci_resource_end(pci_dev, idx),
(unsigned long long)pci_resource_flags(pci_dev, idx));
if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
memlen = pci_resource_len(pci_dev, idx);
adapter.ap_remapped_mem_base[idx] =
ioremap(pci_resource_start(pci_dev, idx),
memlen);
if (!adapter.ap_remapped_mem_base[idx]) {
HPI_DEBUG_LOG(ERROR,
"ioremap failed, aborting\n");
/* unmap previously mapped pci mem space */
goto err;
}
}
pci.ap_mem_base[idx] = adapter.ap_remapped_mem_base[idx];
}
/* could replace Pci with direct pointer to pci_dev for linux
Instead wrap accessor functions for IDs etc.
Would it work for windows?
*/
pci.bus_number = pci_dev->bus->number;
pci.vendor_id = (u16)pci_dev->vendor;
pci.device_id = (u16)pci_dev->device;
pci.subsys_vendor_id = (u16)(pci_dev->subsystem_vendor & 0xffff);
pci.subsys_device_id = (u16)(pci_dev->subsystem_device & 0xffff);
pci.device_number = pci_dev->devfn;
pci.interrupt = pci_dev->irq;
pci.p_os_data = pci_dev;
hm.u.s.resource.bus_type = HPI_BUS_PCI;
hm.u.s.resource.r.pci = &pci;
/* call CreateAdapterObject on the relevant hpi module */
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
if (hr.error)
goto err;
if (prealloc_stream_buf) {
adapter.p_buffer = vmalloc(prealloc_stream_buf);
if (!adapter.p_buffer) {
HPI_DEBUG_LOG(ERROR,
"HPI could not allocate "
"kernel buffer size %d\n",
prealloc_stream_buf);
goto err;
}
}
adapter.index = hr.u.s.adapter_index;
adapter.type = hr.u.s.aw_adapter_list[adapter.index];
hm.adapter_index = adapter.index;
err = hpi_adapter_open(NULL, adapter.index);
if (err)
goto err;
adapter.snd_card_asihpi = NULL;
/* WARNING can't init mutex in 'adapter'
* and then copy it to adapters[] ?!?!
*/
adapters[hr.u.s.adapter_index] = adapter;
mutex_init(&adapters[adapter.index].mutex);
pci_set_drvdata(pci_dev, &adapters[adapter.index]);
printk(KERN_INFO "probe found adapter ASI%04X HPI index #%d.\n",
adapter.type, adapter.index);
return 0;
err:
for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
if (adapter.ap_remapped_mem_base[idx]) {
iounmap(adapter.ap_remapped_mem_base[idx]);
adapter.ap_remapped_mem_base[idx] = NULL;
}
}
if (adapter.p_buffer) {
adapter.buffer_size = 0;
vfree(adapter.p_buffer);
}
HPI_DEBUG_LOG(ERROR, "adapter_probe failed\n");
return -ENODEV;
}
void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
{
int idx;
struct hpi_message hm;
struct hpi_response hr;
struct hpi_adapter *pa;
pa = (struct hpi_adapter *)pci_get_drvdata(pci_dev);
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DELETE_ADAPTER);
hm.adapter_index = pa->index;
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
/* unmap PCI memory space, mapped during device init. */
for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
if (pa->ap_remapped_mem_base[idx]) {
iounmap(pa->ap_remapped_mem_base[idx]);
pa->ap_remapped_mem_base[idx] = NULL;
}
}
if (pa->p_buffer) {
pa->buffer_size = 0;
vfree(pa->p_buffer);
}
pci_set_drvdata(pci_dev, NULL);
/*
printk(KERN_INFO "PCI device (%04x:%04x,%04x:%04x,%04x),"
" HPI index # %d, removed.\n",
pci_dev->vendor, pci_dev->device,
pci_dev->subsystem_vendor,
pci_dev->subsystem_device, pci_dev->devfn,
pa->index);
*/
}
void __init asihpi_init(void)
{
struct hpi_message hm;
struct hpi_response hr;
memset(adapters, 0, sizeof(adapters));
printk(KERN_INFO "ASIHPI driver %d.%02d.%02d\n",
HPI_VER_MAJOR(HPI_VER), HPI_VER_MINOR(HPI_VER),
HPI_VER_RELEASE(HPI_VER));
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DRIVER_LOAD);
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
}
void asihpi_exit(void)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DRIVER_UNLOAD);
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
}

View File

@ -0,0 +1,38 @@
/*******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linux HPI ioctl, and shared module init functions
*******************************************************************************/
int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id);
void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev);
void __init asihpi_init(void);
void __exit asihpi_exit(void);
int asihpi_hpi_release(struct file *file);
long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/* This is called from hpifunc.c functions, called by ALSA
* (or other kernel process) In this case there is no file descriptor
* available for the message cache code
*/
void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr);
#define HOWNER_KERNEL ((void *)-1)

114
sound/pci/asihpi/hpios.c Normal file
View File

@ -0,0 +1,114 @@
/******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
HPI Operating System function implementation for Linux
(C) Copyright AudioScience Inc. 1997-2003
******************************************************************************/
#define SOURCEFILE_NAME "hpios.c"
#include "hpi_internal.h"
#include "hpidebug.h"
#include <linux/delay.h>
#include <linux/sched.h>
void hpios_delay_micro_seconds(u32 num_micro_sec)
{
if ((usecs_to_jiffies(num_micro_sec) > 1) && !in_interrupt()) {
/* MUST NOT SCHEDULE IN INTERRUPT CONTEXT! */
schedule_timeout_uninterruptible(usecs_to_jiffies
(num_micro_sec));
} else if (num_micro_sec <= 2000)
udelay(num_micro_sec);
else
mdelay(num_micro_sec / 1000);
}
void hpios_locked_mem_init(void)
{
}
/** Allocated an area of locked memory for bus master DMA operations.
On error, return -ENOMEM, and *pMemArea.size = 0
*/
u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size,
struct pci_dev *pdev)
{
/*?? any benefit in using managed dmam_alloc_coherent? */
p_mem_area->vaddr =
dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle,
GFP_DMA32 | GFP_KERNEL);
if (p_mem_area->vaddr) {
HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n",
size, (unsigned int)p_mem_area->dma_handle,
p_mem_area->vaddr);
p_mem_area->pdev = &pdev->dev;
p_mem_area->size = size;
return 0;
} else {
HPI_DEBUG_LOG(WARNING,
"failed to allocate %d bytes locked memory\n", size);
p_mem_area->size = 0;
return -ENOMEM;
}
}
u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area)
{
if (p_mem_area->size) {
dma_free_coherent(p_mem_area->pdev, p_mem_area->size,
p_mem_area->vaddr, p_mem_area->dma_handle);
HPI_DEBUG_LOG(DEBUG, "freed %lu bytes, dma 0x%x vma %p\n",
(unsigned long)p_mem_area->size,
(unsigned int)p_mem_area->dma_handle,
p_mem_area->vaddr);
p_mem_area->size = 0;
return 0;
} else {
return 1;
}
}
void hpios_locked_mem_free_all(void)
{
}
void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
unsigned int length)
{
HPI_DEBUG_LOG(DEBUG, "mapping %d %s %08llx-%08llx %04llx len 0x%x\n",
idx, pci_dev->resource[idx].name,
(unsigned long long)pci_resource_start(pci_dev, idx),
(unsigned long long)pci_resource_end(pci_dev, idx),
(unsigned long long)pci_resource_flags(pci_dev, idx), length);
if (!(pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM)) {
HPI_DEBUG_LOG(ERROR, "not an io memory resource\n");
return NULL;
}
if (length > pci_resource_len(pci_dev, idx)) {
HPI_DEBUG_LOG(ERROR, "resource too small for requested %d \n",
length);
return NULL;
}
return ioremap(pci_resource_start(pci_dev, idx), length);
}

178
sound/pci/asihpi/hpios.h Normal file
View File

@ -0,0 +1,178 @@
/******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
HPI Operating System Specific macros for Linux Kernel driver
(C) Copyright AudioScience Inc. 1997-2003
******************************************************************************/
#ifndef _HPIOS_H_
#define _HPIOS_H_
#undef HPI_OS_LINUX_KERNEL
#define HPI_OS_LINUX_KERNEL
#define HPI_OS_DEFINED
#define HPI_KERNEL_MODE
#define HPI_REASSIGN_DUPLICATE_ADAPTER_IDX
#include <linux/io.h>
#include <asm/system.h>
#include <linux/ioctl.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#define HPI_NO_OS_FILE_OPS
#ifdef CONFIG_64BIT
#define HPI64BIT
#endif
/** Details of a memory area allocated with pci_alloc_consistent
Need all info for parameters to pci_free_consistent
*/
struct consistent_dma_area {
struct device *pdev;
/* looks like dma-mapping dma_devres ?! */
size_t size;
void *vaddr;
dma_addr_t dma_handle;
};
static inline u16 hpios_locked_mem_get_phys_addr(struct consistent_dma_area
*locked_mem_handle, u32 *p_physical_addr)
{
*p_physical_addr = locked_mem_handle->dma_handle;
return 0;
}
static inline u16 hpios_locked_mem_get_virt_addr(struct consistent_dma_area
*locked_mem_handle, void **pp_virtual_addr)
{
*pp_virtual_addr = locked_mem_handle->vaddr;
return 0;
}
static inline u16 hpios_locked_mem_valid(struct consistent_dma_area
*locked_mem_handle)
{
return locked_mem_handle->size != 0;
}
struct hpi_ioctl_linux {
void __user *phm;
void __user *phr;
};
/* Conflict?: H is already used by a number of drivers hid, bluetooth hci,
and some sound drivers sb16, hdsp, emu10k. AFAIK 0xFC is ununsed command
*/
#define HPI_IOCTL_LINUX _IOWR('H', 0xFC, struct hpi_ioctl_linux)
#define HPI_DEBUG_FLAG_ERROR KERN_ERR
#define HPI_DEBUG_FLAG_WARNING KERN_WARNING
#define HPI_DEBUG_FLAG_NOTICE KERN_NOTICE
#define HPI_DEBUG_FLAG_INFO KERN_INFO
#define HPI_DEBUG_FLAG_DEBUG KERN_DEBUG
#define HPI_DEBUG_FLAG_VERBOSE KERN_DEBUG /* kernel has no verbose */
#include <linux/spinlock.h>
#define HPI_LOCKING
struct hpios_spinlock {
spinlock_t lock; /* SEE hpios_spinlock */
int lock_context;
};
/* The reason for all this evilness is that ALSA calls some of a drivers
* operators in atomic context, and some not. But all our functions channel
* through the HPI_Message conduit, so we can't handle the different context
* per function
*/
#define IN_LOCK_BH 1
#define IN_LOCK_IRQ 0
static inline void cond_lock(struct hpios_spinlock *l)
{
if (irqs_disabled()) {
/* NO bh or isr can execute on this processor,
so ordinary lock will do
*/
spin_lock(&((l)->lock));
l->lock_context = IN_LOCK_IRQ;
} else {
spin_lock_bh(&((l)->lock));
l->lock_context = IN_LOCK_BH;
}
}
static inline void cond_unlock(struct hpios_spinlock *l)
{
if (l->lock_context == IN_LOCK_BH)
spin_unlock_bh(&((l)->lock));
else
spin_unlock(&((l)->lock));
}
#define hpios_msgxlock_init(obj) spin_lock_init(&(obj)->lock)
#define hpios_msgxlock_lock(obj) cond_lock(obj)
#define hpios_msgxlock_un_lock(obj) cond_unlock(obj)
#define hpios_dsplock_init(obj) spin_lock_init(&(obj)->dsp_lock.lock)
#define hpios_dsplock_lock(obj) cond_lock(&(obj)->dsp_lock)
#define hpios_dsplock_unlock(obj) cond_unlock(&(obj)->dsp_lock)
#ifdef CONFIG_SND_DEBUG
#define HPI_DEBUG
#endif
#define HPI_ALIST_LOCKING
#define hpios_alistlock_init(obj) spin_lock_init(&((obj)->list_lock.lock))
#define hpios_alistlock_lock(obj) spin_lock(&((obj)->list_lock.lock))
#define hpios_alistlock_un_lock(obj) spin_unlock(&((obj)->list_lock.lock))
struct hpi_adapter {
/* mutex prevents contention for one card
between multiple user programs (via ioctl) */
struct mutex mutex;
u16 index;
u16 type;
/* ALSA card structure */
void *snd_card_asihpi;
char *p_buffer;
size_t buffer_size;
struct pci_dev *pci;
void __iomem *ap_remapped_mem_base[HPI_MAX_ADAPTER_MEM_SPACES];
};
static inline void hpios_unmap_io(void __iomem *addr,
unsigned long size)
{
iounmap(addr);
}
void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
unsigned int length);
#endif

View File

@ -0,0 +1,37 @@
/******************************************************************************
AudioScience HPI driver
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
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
published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Array initializer for PCI card IDs
(C) Copyright AudioScience Inc. 1998-2003
*******************************************************************************/
/*NOTE: when adding new lines to this header file
they MUST be grouped by HPI entry point.
*/
{
HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
(kernel_ulong_t) HPI_6205}
, {
HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
(kernel_ulong_t) HPI_6000}
, {
0}