mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 13:41:51 +00:00
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:
parent
cf0dbba515
commit
719f82d398
@ -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
|
||||
-----------------
|
||||
|
||||
|
@ -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
|
||||
|
@ -57,6 +57,7 @@ obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o
|
||||
obj-$(CONFIG_SND) += \
|
||||
ac97/ \
|
||||
ali5451/ \
|
||||
asihpi/ \
|
||||
au88x0/ \
|
||||
aw2/ \
|
||||
ctxfi/ \
|
||||
|
5
sound/pci/asihpi/Makefile
Normal file
5
sound/pci/asihpi/Makefile
Normal 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
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
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
1841
sound/pci/asihpi/hpi6000.c
Normal file
File diff suppressed because it is too large
Load Diff
70
sound/pci/asihpi/hpi6000.h
Normal file
70
sound/pci/asihpi/hpi6000.h
Normal 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
2332
sound/pci/asihpi/hpi6205.c
Normal file
File diff suppressed because it is too large
Load Diff
93
sound/pci/asihpi/hpi6205.h
Normal file
93
sound/pci/asihpi/hpi6205.h
Normal 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
|
1641
sound/pci/asihpi/hpi_internal.h
Normal file
1641
sound/pci/asihpi/hpi_internal.h
Normal file
File diff suppressed because it is too large
Load Diff
643
sound/pci/asihpi/hpicmn.c
Normal file
643
sound/pci/asihpi/hpicmn.c
Normal 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
64
sound/pci/asihpi/hpicmn.h
Normal 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
225
sound/pci/asihpi/hpidebug.c
Normal 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
385
sound/pci/asihpi/hpidebug.h
Normal 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
172
sound/pci/asihpi/hpidspcd.c
Normal 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
104
sound/pci/asihpi/hpidspcd.h
Normal 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
3864
sound/pci/asihpi/hpifunc.c
Normal file
File diff suppressed because it is too large
Load Diff
130
sound/pci/asihpi/hpimsginit.c
Normal file
130
sound/pci/asihpi/hpimsginit.c
Normal 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);
|
||||
}
|
40
sound/pci/asihpi/hpimsginit.h
Normal file
40
sound/pci/asihpi/hpimsginit.h
Normal 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
907
sound/pci/asihpi/hpimsgx.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
sound/pci/asihpi/hpimsgx.h
Normal file
36
sound/pci/asihpi/hpimsgx.h
Normal 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
484
sound/pci/asihpi/hpioctl.c
Normal 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);
|
||||
}
|
38
sound/pci/asihpi/hpioctl.h
Normal file
38
sound/pci/asihpi/hpioctl.h
Normal 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
114
sound/pci/asihpi/hpios.c
Normal 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
178
sound/pci/asihpi/hpios.h
Normal 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
|
37
sound/pci/asihpi/hpipcida.h
Normal file
37
sound/pci/asihpi/hpipcida.h
Normal 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}
|
Loading…
Reference in New Issue
Block a user