mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 01:08:03 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
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
|
2995
sound/pci/asihpi/asihpi.c
Normal file
2995
sound/pci/asihpi/asihpi.c
Normal file
File diff suppressed because it is too large
Load diff
1727
sound/pci/asihpi/hpi.h
Normal file
1727
sound/pci/asihpi/hpi.h
Normal file
File diff suppressed because it is too large
Load diff
1809
sound/pci/asihpi/hpi6000.c
Normal file
1809
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-2011 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_ */
|
2208
sound/pci/asihpi/hpi6205.c
Normal file
2208
sound/pci/asihpi/hpi6205.c
Normal file
File diff suppressed because it is too large
Load diff
103
sound/pci/asihpi/hpi6205.h
Normal file
103
sound/pci/asihpi/hpi6205.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*****************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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_
|
||||
|
||||
#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 message_buffer_6205 {
|
||||
struct hpi_message message;
|
||||
char data[256];
|
||||
};
|
||||
|
||||
struct response_buffer_6205 {
|
||||
struct hpi_response response;
|
||||
char data[256];
|
||||
};
|
||||
|
||||
union buffer_6205 {
|
||||
struct message_buffer_6205 message_buffer;
|
||||
struct response_buffer_6205 response_buffer;
|
||||
u8 b_data[HPI6205_SIZEOF_DATA];
|
||||
};
|
||||
|
||||
struct bus_master_interface {
|
||||
u32 host_cmd;
|
||||
u32 dsp_ack;
|
||||
u32 transfer_size_in_bytes;
|
||||
union buffer_6205 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
|
1431
sound/pci/asihpi/hpi_internal.h
Normal file
1431
sound/pci/asihpi/hpi_internal.h
Normal file
File diff suppressed because it is too large
Load diff
32
sound/pci/asihpi/hpi_version.h
Normal file
32
sound/pci/asihpi/hpi_version.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/** HPI Version Definitions
|
||||
Development releases have odd minor version.
|
||||
Production releases have even minor version.
|
||||
|
||||
\file hpi_version.h
|
||||
*/
|
||||
|
||||
#ifndef _HPI_VERSION_H
|
||||
#define _HPI_VERSION_H
|
||||
|
||||
/* Use single digits for versions less that 10 to avoid octal. */
|
||||
/* *** HPI_VER is the only edit required to update version *** */
|
||||
/** HPI version */
|
||||
#define HPI_VER HPI_VERSION_CONSTRUCTOR(4, 10, 1)
|
||||
|
||||
/** HPI version string in dotted decimal format */
|
||||
#define HPI_VER_STRING "4.10.01"
|
||||
|
||||
/** Library version as documented in hpi-api-versions.txt */
|
||||
#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(10, 2, 0)
|
||||
|
||||
/** Construct hpi version number from major, minor, release numbers */
|
||||
#define HPI_VERSION_CONSTRUCTOR(maj, min, r) ((maj << 16) + (min << 8) + r)
|
||||
|
||||
/** Extract major version from hpi version number */
|
||||
#define HPI_VER_MAJOR(v) ((int)(v >> 16))
|
||||
/** Extract minor version from hpi version number */
|
||||
#define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF))
|
||||
/** Extract release from hpi version number */
|
||||
#define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
|
||||
|
||||
#endif
|
703
sound/pci/asihpi/hpicmn.c
Normal file
703
sound/pci/asihpi/hpicmn.c
Normal file
|
@ -0,0 +1,703 @@
|
|||
/******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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 "hpimsginit.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)
|
||||
{
|
||||
if (phr->type != HPI_TYPE_RESPONSE) {
|
||||
HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type);
|
||||
return HPI_ERROR_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
if (phr->object != phm->object) {
|
||||
HPI_DEBUG_LOG(ERROR, "header object %d invalid\n",
|
||||
phr->object);
|
||||
return HPI_ERROR_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
if (phr->function != phm->function) {
|
||||
HPI_DEBUG_LOG(ERROR, "header function %d invalid\n",
|
||||
phr->function);
|
||||
return HPI_ERROR_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
|
||||
{
|
||||
u16 retval = 0;
|
||||
/*HPI_ASSERT(pao->type); */
|
||||
|
||||
hpios_alistlock_lock(&adapters);
|
||||
|
||||
if (pao->index >= HPI_MAX_ADAPTERS) {
|
||||
retval = HPI_ERROR_BAD_ADAPTER_NUMBER;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (adapters.adapter[pao->index].type) {
|
||||
int a;
|
||||
for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) {
|
||||
if (!adapters.adapter[a].type) {
|
||||
HPI_DEBUG_LOG(WARNING,
|
||||
"ASI%X duplicate index %d moved to %d\n",
|
||||
pao->type, pao->index, a);
|
||||
pao->index = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (a < 0) {
|
||||
retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
adapters.adapter[pao->index] = *pao;
|
||||
hpios_dsplock_init(&adapters.adapter[pao->index]);
|
||||
adapters.gw_num_adapters++;
|
||||
|
||||
unlock:
|
||||
hpios_alistlock_unlock(&adapters);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void hpi_delete_adapter(struct hpi_adapter_obj *pao)
|
||||
{
|
||||
if (!pao->type) {
|
||||
HPI_DEBUG_LOG(ERROR, "removing null adapter?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hpios_alistlock_lock(&adapters);
|
||||
if (adapters.adapter[pao->index].type)
|
||||
adapters.gw_num_adapters--;
|
||||
memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0]));
|
||||
hpios_alistlock_unlock(&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\n",
|
||||
adapter_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pao = &adapters.adapter[adapter_index];
|
||||
if (pao->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));
|
||||
}
|
||||
|
||||
static void subsys_get_adapter(struct hpi_message *phm,
|
||||
struct hpi_response *phr)
|
||||
{
|
||||
int count = phm->obj_index;
|
||||
u16 index = 0;
|
||||
|
||||
/* find the nCount'th nonzero adapter in array */
|
||||
for (index = 0; index < HPI_MAX_ADAPTERS; index++) {
|
||||
if (adapters.adapter[index].type) {
|
||||
if (!count)
|
||||
break;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < HPI_MAX_ADAPTERS) {
|
||||
phr->u.s.adapter_index = adapters.adapter[index].index;
|
||||
phr->u.s.adapter_type = adapters.adapter[index].type;
|
||||
} else {
|
||||
phr->u.s.adapter_index = 0;
|
||||
phr->u.s.adapter_type = 0;
|
||||
phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
return pC->init;
|
||||
|
||||
if (!pC->p_cache)
|
||||
return 0;
|
||||
|
||||
if (pC->control_count && pC->cache_size_in_bytes) {
|
||||
char *p_master_cache;
|
||||
unsigned int byte_count = 0;
|
||||
|
||||
p_master_cache = (char *)pC->p_cache;
|
||||
HPI_DEBUG_LOG(DEBUG, "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[byte_count];
|
||||
|
||||
if (!info->size_in32bit_words) {
|
||||
if (!i) {
|
||||
HPI_DEBUG_LOG(INFO,
|
||||
"adap %d cache not ready?\n",
|
||||
pC->adap_idx);
|
||||
return 0;
|
||||
}
|
||||
/* The cache is invalid.
|
||||
* Minimum valid entry size is
|
||||
* sizeof(struct hpi_control_cache_info)
|
||||
*/
|
||||
HPI_DEBUG_LOG(ERROR,
|
||||
"adap %d zero size cache entry %d\n",
|
||||
pC->adap_idx, i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (info->control_type) {
|
||||
pC->p_info[info->control_index] = info;
|
||||
cached++;
|
||||
} else { /* dummy cache entry */
|
||||
pC->p_info[info->control_index] = NULL;
|
||||
}
|
||||
|
||||
byte_count += info->size_in32bit_words * 4;
|
||||
|
||||
HPI_DEBUG_LOG(VERBOSE,
|
||||
"cached %d, pinfo %p index %d type %d size %d\n",
|
||||
cached, pC->p_info[info->control_index],
|
||||
info->control_index, info->control_type,
|
||||
info->size_in32bit_words);
|
||||
|
||||
/* quit loop early if whole cache has been scanned.
|
||||
* dwControlCount is the maximum possible entries
|
||||
* but some may be absent from the cache
|
||||
*/
|
||||
if (byte_count >= pC->cache_size_in_bytes)
|
||||
break;
|
||||
/* have seen last control index */
|
||||
if (info->control_index == pC->control_count - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (byte_count != pC->cache_size_in_bytes)
|
||||
HPI_DEBUG_LOG(WARNING,
|
||||
"adap %d bytecount %d != cache size %d\n",
|
||||
pC->adap_idx, byte_count,
|
||||
pC->cache_size_in_bytes);
|
||||
else
|
||||
HPI_DEBUG_LOG(DEBUG,
|
||||
"adap %d cache good, bytecount == cache size = %d\n",
|
||||
pC->adap_idx, byte_count);
|
||||
|
||||
pC->init = (u16)cached;
|
||||
}
|
||||
return pC->init;
|
||||
}
|
||||
|
||||
/** Find a control.
|
||||
*/
|
||||
static short find_control(u16 control_index,
|
||||
struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
|
||||
{
|
||||
if (!control_cache_alloc_check(p_cache)) {
|
||||
HPI_DEBUG_LOG(VERBOSE,
|
||||
"control_cache_alloc_check() failed %d\n",
|
||||
control_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pI = p_cache->p_info[control_index];
|
||||
if (!*pI) {
|
||||
HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
|
||||
control_index);
|
||||
return 0;
|
||||
} else {
|
||||
HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
|
||||
(*pI)->control_type);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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 const 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;
|
||||
struct hpi_control_cache_info *pI;
|
||||
struct hpi_control_cache_single *pC;
|
||||
size_t response_size;
|
||||
if (!find_control(phm->obj_index, p_cache, &pI)) {
|
||||
HPI_DEBUG_LOG(VERBOSE,
|
||||
"HPICMN find_control() failed for adap %d\n",
|
||||
phm->adapter_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
phr->error = 0;
|
||||
phr->specific_error = 0;
|
||||
phr->version = 0;
|
||||
|
||||
/* set the default response size */
|
||||
response_size =
|
||||
sizeof(struct hpi_response_header) +
|
||||
sizeof(struct hpi_control_res);
|
||||
|
||||
/* 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_METER:
|
||||
if (phm->u.c.attribute == HPI_METER_PEAK) {
|
||||
phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
|
||||
phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
|
||||
} else if (phm->u.c.attribute == HPI_METER_RMS) {
|
||||
if (pC->u.meter.an_logRMS[0] ==
|
||||
HPI_CACHE_INVALID_SHORT) {
|
||||
phr->error =
|
||||
HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
|
||||
phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
|
||||
phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
|
||||
} else {
|
||||
phr->u.c.an_log_value[0] =
|
||||
pC->u.meter.an_logRMS[0];
|
||||
phr->u.c.an_log_value[1] =
|
||||
pC->u.meter.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.vol.an_log[0];
|
||||
phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
|
||||
} else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
|
||||
if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) {
|
||||
if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED)
|
||||
phr->u.c.param1 =
|
||||
HPI_BITMASK_ALL_CHANNELS;
|
||||
else
|
||||
phr->u.c.param1 = 0;
|
||||
} else {
|
||||
phr->error =
|
||||
HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
|
||||
phr->u.c.param1 = 0;
|
||||
}
|
||||
} else {
|
||||
found = 0;
|
||||
}
|
||||
break;
|
||||
case HPI_CONTROL_MULTIPLEXER:
|
||||
if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
|
||||
phr->u.c.param1 = pC->u.mux.source_node_type;
|
||||
phr->u.c.param2 = pC->u.mux.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.mode.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.level.an_log[0];
|
||||
phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
|
||||
} else
|
||||
found = 0;
|
||||
break;
|
||||
case HPI_CONTROL_TUNER:
|
||||
if (phm->u.c.attribute == HPI_TUNER_FREQ)
|
||||
phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
|
||||
else if (phm->u.c.attribute == HPI_TUNER_BAND)
|
||||
phr->u.c.param1 = pC->u.tuner.band;
|
||||
else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
|
||||
if (pC->u.tuner.s_level_avg ==
|
||||
HPI_CACHE_INVALID_SHORT) {
|
||||
phr->u.cu.tuner.s_level = 0;
|
||||
phr->error =
|
||||
HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
|
||||
} else
|
||||
phr->u.cu.tuner.s_level =
|
||||
pC->u.tuner.s_level_avg;
|
||||
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.format;
|
||||
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;
|
||||
} else
|
||||
found = 0;
|
||||
break;
|
||||
case HPI_CONTROL_MICROPHONE:
|
||||
if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
|
||||
phr->u.c.param1 = pC->u.microphone.phantom_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_CACHE_INVALID_UINT16) {
|
||||
phr->u.c.param1 = 0;
|
||||
phr->error =
|
||||
HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
|
||||
} 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:{
|
||||
struct hpi_control_cache_pad *p_pad;
|
||||
p_pad = (struct hpi_control_cache_pad *)pI;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
|
||||
found ? "Cached" : "Uncached", phm->adapter_index,
|
||||
pI->control_index, pI->control_type, phm->u.c.attribute);
|
||||
|
||||
if (found) {
|
||||
phr->size = (u16)response_size;
|
||||
phr->type = HPI_TYPE_RESPONSE;
|
||||
phr->object = phm->object;
|
||||
phr->function = phm->function;
|
||||
}
|
||||
|
||||
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_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
|
||||
struct hpi_message *phm, struct hpi_response *phr)
|
||||
{
|
||||
struct hpi_control_cache_single *pC;
|
||||
struct hpi_control_cache_info *pI;
|
||||
|
||||
if (phr->error)
|
||||
return;
|
||||
|
||||
if (!find_control(phm->obj_index, p_cache, &pI)) {
|
||||
HPI_DEBUG_LOG(VERBOSE,
|
||||
"HPICMN find_control() failed for adap %d\n",
|
||||
phm->adapter_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.vol.an_log[0] = phr->u.c.an_log_value[0];
|
||||
pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
|
||||
} else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
|
||||
if (phm->u.c.param1)
|
||||
pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED;
|
||||
else
|
||||
pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED;
|
||||
}
|
||||
break;
|
||||
case HPI_CONTROL_MULTIPLEXER:
|
||||
/* mux does not return its setting on Set command. */
|
||||
if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
|
||||
pC->u.mux.source_node_type = (u16)phm->u.c.param1;
|
||||
pC->u.mux.source_node_index = (u16)phm->u.c.param2;
|
||||
}
|
||||
break;
|
||||
case HPI_CONTROL_CHANNEL_MODE:
|
||||
/* mode does not return its setting on Set command. */
|
||||
if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
|
||||
pC->u.mode.mode = (u16)phm->u.c.param1;
|
||||
break;
|
||||
case HPI_CONTROL_LEVEL:
|
||||
if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
|
||||
pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
|
||||
pC->u.vol.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.microphone.phantom_state = (u16)phm->u.c.param1;
|
||||
break;
|
||||
case HPI_CONTROL_AESEBU_TRANSMITTER:
|
||||
if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
|
||||
pC->u.aes3tx.format = phm->u.c.param1;
|
||||
break;
|
||||
case HPI_CONTROL_AESEBU_RECEIVER:
|
||||
if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
|
||||
pC->u.aes3rx.format = phm->u.c.param1;
|
||||
break;
|
||||
case HPI_CONTROL_SAMPLECLOCK:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/** Allocate control cache.
|
||||
|
||||
\return Cache pointer, or NULL if allocation fails.
|
||||
*/
|
||||
struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
|
||||
const u32 size_in_bytes, u8 *p_dsp_control_buffer)
|
||||
{
|
||||
struct hpi_control_cache *p_cache =
|
||||
kmalloc(sizeof(*p_cache), GFP_KERNEL);
|
||||
if (!p_cache)
|
||||
return NULL;
|
||||
|
||||
p_cache->p_info = kcalloc(control_count, sizeof(*p_cache->p_info),
|
||||
GFP_KERNEL);
|
||||
if (!p_cache->p_info) {
|
||||
kfree(p_cache);
|
||||
return NULL;
|
||||
}
|
||||
p_cache->cache_size_in_bytes = size_in_bytes;
|
||||
p_cache->control_count = control_count;
|
||||
p_cache->p_cache = p_dsp_control_buffer;
|
||||
p_cache->init = 0;
|
||||
return p_cache;
|
||||
}
|
||||
|
||||
void hpi_free_control_cache(struct hpi_control_cache *p_cache)
|
||||
{
|
||||
if (p_cache) {
|
||||
kfree(p_cache->p_info);
|
||||
kfree(p_cache);
|
||||
}
|
||||
}
|
||||
|
||||
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
|
||||
{
|
||||
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
|
||||
|
||||
switch (phm->function) {
|
||||
case HPI_SUBSYS_OPEN:
|
||||
case HPI_SUBSYS_CLOSE:
|
||||
case HPI_SUBSYS_DRIVER_UNLOAD:
|
||||
break;
|
||||
case HPI_SUBSYS_DRIVER_LOAD:
|
||||
wipe_adapter_list();
|
||||
hpios_alistlock_init(&adapters);
|
||||
break;
|
||||
case HPI_SUBSYS_GET_ADAPTER:
|
||||
subsys_get_adapter(phm, phr);
|
||||
break;
|
||||
case HPI_SUBSYS_GET_NUM_ADAPTERS:
|
||||
phr->u.s.num_adapters = adapters.gw_num_adapters;
|
||||
break;
|
||||
case HPI_SUBSYS_CREATE_ADAPTER:
|
||||
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_REQUEST:
|
||||
switch (phm->object) {
|
||||
case HPI_OBJ_SUBSYSTEM:
|
||||
subsys_message(phm, phr);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
phr->error = HPI_ERROR_INVALID_TYPE;
|
||||
break;
|
||||
}
|
||||
}
|
67
sound/pci/asihpi/hpicmn.h
Normal file
67
sound/pci/asihpi/hpicmn.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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;
|
||||
|
||||
/* a function that takes an adapter obj and returns an int */
|
||||
typedef int adapter_int_func(struct hpi_adapter_obj *pao);
|
||||
|
||||
struct hpi_adapter_obj {
|
||||
struct hpi_pci pci; /* PCI info - bus#,dev#,address etc */
|
||||
u16 type; /* 0x6644 == ASI6644 etc */
|
||||
u16 index;
|
||||
|
||||
struct hpios_spinlock dsp_lock;
|
||||
|
||||
u16 dsp_crashed;
|
||||
u16 has_control_cache;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct hpi_control_cache {
|
||||
/** indicates whether the structures are initialized */
|
||||
u16 init;
|
||||
u16 adap_idx;
|
||||
u32 control_count;
|
||||
u32 cache_size_in_bytes;
|
||||
/** pointer to allocated memory of lookup pointers. */
|
||||
struct hpi_control_cache_info **p_info;
|
||||
/** pointer to DSP's control cache. */
|
||||
u8 *p_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, u8 *pDSP_control_buffer);
|
||||
void hpi_free_control_cache(struct hpi_control_cache *p_cache);
|
||||
|
||||
void hpi_cmn_control_cache_sync_to_msg(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);
|
||||
|
||||
hpi_handler_func HPI_COMMON;
|
78
sound/pci/asihpi/hpidebug.c
Normal file
78
sound/pci/asihpi/hpidebug.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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;
|
||||
}
|
||||
|
||||
void hpi_debug_message(struct hpi_message *phm, char *sz_fileline)
|
||||
{
|
||||
if (phm) {
|
||||
printk(KERN_DEBUG "HPI_MSG%d,%d,%d,%d,%d\n", phm->version,
|
||||
phm->adapter_index, phm->obj_index, phm->function,
|
||||
phm->u.c.attribute);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
102
sound/pci/asihpi/hpidebug.h
Normal file
102
sound/pci/asihpi/hpidebug.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*****************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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 linux kernel hpios.h */
|
||||
|
||||
#ifdef SOURCEFILE_NAME
|
||||
#define FILE_LINE SOURCEFILE_NAME ":" __stringify(__LINE__) " "
|
||||
#else
|
||||
#define FILE_LINE __FILE__ ":" __stringify(__LINE__) " "
|
||||
#endif
|
||||
|
||||
#define HPI_DEBUG_ASSERT(expression) \
|
||||
do { \
|
||||
if (!(expression)) { \
|
||||
printk(KERN_ERR FILE_LINE \
|
||||
"ASSERT " __stringify(expression)); \
|
||||
} \
|
||||
} 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_level >= HPI_DEBUG_LEVEL_VERBOSE)) \
|
||||
printk(KERN_DEBUG "HPI_RES%d,%d,%d\n", \
|
||||
phr->version, phr->error, phr->specific_error); \
|
||||
} while (0)
|
||||
|
||||
#ifndef compile_time_assert
|
||||
#define compile_time_assert(cond, msg) \
|
||||
typedef char msg[(cond) ? 1 : -1]
|
||||
#endif
|
||||
|
||||
#endif /* _HPIDEBUG_H_ */
|
144
sound/pci/asihpi/hpidspcd.c
Normal file
144
sound/pci/asihpi/hpidspcd.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/***********************************************************************/
|
||||
/**
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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 using
|
||||
hotplug firmware loader from individual dsp code files
|
||||
*/
|
||||
/***********************************************************************/
|
||||
#define SOURCEFILE_NAME "hpidspcd.c"
|
||||
#include "hpidspcd.h"
|
||||
#include "hpidebug.h"
|
||||
#include "hpi_version.h"
|
||||
|
||||
struct dsp_code_private {
|
||||
/** Firmware descriptor */
|
||||
const struct firmware *firmware;
|
||||
struct pci_dev *dev;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
|
||||
u32 *os_error_code)
|
||||
{
|
||||
const struct firmware *firmware;
|
||||
struct pci_dev *dev = os_data;
|
||||
struct code_header header;
|
||||
char fw_name[20];
|
||||
short err_ret = HPI_ERROR_DSP_FILE_NOT_FOUND;
|
||||
int err;
|
||||
|
||||
sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
|
||||
|
||||
err = request_firmware(&firmware, fw_name, &dev->dev);
|
||||
|
||||
if (err || !firmware) {
|
||||
dev_err(&dev->dev, "%d, request_firmware failed for %s\n",
|
||||
err, fw_name);
|
||||
goto error1;
|
||||
}
|
||||
if (firmware->size < sizeof(header)) {
|
||||
dev_err(&dev->dev, "Header size too small %s\n", fw_name);
|
||||
goto error2;
|
||||
}
|
||||
memcpy(&header, firmware->data, sizeof(header));
|
||||
|
||||
if ((header.type != 0x45444F43) || /* "CODE" */
|
||||
(header.adapter != adapter)
|
||||
|| (header.size != firmware->size)) {
|
||||
dev_err(&dev->dev,
|
||||
"Invalid firmware header size %d != file %zd\n",
|
||||
header.size, firmware->size);
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if ((header.version >> 9) != (HPI_VER >> 9)) {
|
||||
/* Consider even and subsequent odd minor versions to be compatible */
|
||||
dev_err(&dev->dev, "Incompatible firmware version DSP image %X != Driver %X\n",
|
||||
header.version, HPI_VER);
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if (header.version != HPI_VER) {
|
||||
dev_info(&dev->dev,
|
||||
"Firmware: release version mismatch DSP image %X != Driver %X\n",
|
||||
header.version, HPI_VER);
|
||||
}
|
||||
|
||||
HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
|
||||
dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL);
|
||||
if (!dsp_code->pvt) {
|
||||
err_ret = HPI_ERROR_MEMORY_ALLOC;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
dsp_code->pvt->dev = dev;
|
||||
dsp_code->pvt->firmware = firmware;
|
||||
dsp_code->header = header;
|
||||
dsp_code->block_length = header.size / sizeof(u32);
|
||||
dsp_code->word_count = sizeof(header) / sizeof(u32);
|
||||
return 0;
|
||||
|
||||
error2:
|
||||
release_firmware(firmware);
|
||||
error1:
|
||||
dsp_code->block_length = 0;
|
||||
return err_ret;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
void hpi_dsp_code_close(struct dsp_code *dsp_code)
|
||||
{
|
||||
HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
|
||||
release_firmware(dsp_code->pvt->firmware);
|
||||
kfree(dsp_code->pvt);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
void hpi_dsp_code_rewind(struct dsp_code *dsp_code)
|
||||
{
|
||||
/* Go back to start of data, after header */
|
||||
dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
short hpi_dsp_code_read_word(struct dsp_code *dsp_code, u32 *pword)
|
||||
{
|
||||
if (dsp_code->word_count + 1 > dsp_code->block_length)
|
||||
return HPI_ERROR_DSP_FILE_FORMAT;
|
||||
|
||||
*pword = ((u32 *)(dsp_code->pvt->firmware->data))[dsp_code->
|
||||
word_count];
|
||||
dsp_code->word_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
short hpi_dsp_code_read_block(size_t words_requested,
|
||||
struct dsp_code *dsp_code, u32 **ppblock)
|
||||
{
|
||||
if (dsp_code->word_count + words_requested > dsp_code->block_length)
|
||||
return HPI_ERROR_DSP_FILE_FORMAT;
|
||||
|
||||
*ppblock =
|
||||
((u32 *)(dsp_code->pvt->firmware->data)) +
|
||||
dsp_code->word_count;
|
||||
dsp_code->word_count += words_requested;
|
||||
return 0;
|
||||
}
|
106
sound/pci/asihpi/hpidspcd.h
Normal file
106
sound/pci/asihpi/hpidspcd.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/***********************************************************************/
|
||||
/**
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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
|
||||
|
||||
*/
|
||||
/***********************************************************************/
|
||||
#ifndef _HPIDSPCD_H_
|
||||
#define _HPIDSPCD_H_
|
||||
|
||||
#include "hpi_internal.h"
|
||||
|
||||
/** Header structure for dsp firmware file
|
||||
This structure must match that used in s2bin.c for generation of asidsp.bin
|
||||
*/
|
||||
/*#ifndef DISABLE_PRAGMA_PACK1 */
|
||||
/*#pragma pack(push, 1) */
|
||||
/*#endif */
|
||||
struct code_header {
|
||||
/** Size in bytes including header */
|
||||
u32 size;
|
||||
/** File type tag "CODE" == 0x45444F43 */
|
||||
u32 type;
|
||||
/** Adapter model number */
|
||||
u32 adapter;
|
||||
/** Firmware version*/
|
||||
u32 version;
|
||||
/** Data checksum */
|
||||
u32 checksum;
|
||||
};
|
||||
/*#ifndef DISABLE_PRAGMA_PACK1 */
|
||||
/*#pragma pack(pop) */
|
||||
/*#endif */
|
||||
|
||||
/*? Don't need the pragmas? */
|
||||
compile_time_assert((sizeof(struct code_header) == 20), code_header_size);
|
||||
|
||||
/** Descriptor for dspcode from firmware loader */
|
||||
struct dsp_code {
|
||||
/** copy of file header */
|
||||
struct code_header header;
|
||||
/** Expected number of words in the whole dsp code,INCL header */
|
||||
u32 block_length;
|
||||
/** Number of words read so far */
|
||||
u32 word_count;
|
||||
|
||||
/** internal state of DSP code reader */
|
||||
struct dsp_code_private *pvt;
|
||||
};
|
||||
|
||||
/** Prepare *psDspCode to refer to the requested adapter's firmware.
|
||||
Code file name is obtained from HpiOs_GetDspCodePath
|
||||
|
||||
\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, void *pci_dev,
|
||||
/** 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
|
2871
sound/pci/asihpi/hpifunc.c
Normal file
2871
sound/pci/asihpi/hpifunc.c
Normal file
File diff suppressed because it is too large
Load diff
116
sound/pci/asihpi/hpimsginit.c
Normal file
116
sound/pci/asihpi/hpimsginit.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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
|
||||
* 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_REQUEST;
|
||||
phm->object = object;
|
||||
phm->function = function;
|
||||
phm->version = 0;
|
||||
phm->adapter_index = HPI_ADAPTER_INDEX_INVALID;
|
||||
/* Expect actual 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_REQUEST;
|
||||
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);
|
||||
}
|
46
sound/pci/asihpi/hpimsginit.h
Normal file
46
sound/pci/asihpi/hpimsginit.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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 must always be
|
||||
prepared.
|
||||
*/
|
||||
|
||||
#ifndef _HPIMSGINIT_H_
|
||||
#define _HPIMSGINIT_H_
|
||||
|
||||
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);
|
||||
|
||||
#endif /* _HPIMSGINIT_H_ */
|
800
sound/pci/asihpi/hpimsgx.c
Normal file
800
sound/pci/asihpi/hpimsgx.c
Normal file
|
@ -0,0 +1,800 @@
|
|||
/******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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 Caching
|
||||
|
||||
(C) Copyright AudioScience Inc. 2002
|
||||
*****************************************************************************/
|
||||
#define SOURCEFILE_NAME "hpimsgx.c"
|
||||
#include "hpi_internal.h"
|
||||
#include "hpi_version.h"
|
||||
#include "hpimsginit.h"
|
||||
#include "hpicmn.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->pci_dev->vendor)
|
||||
continue;
|
||||
if (asihpi_pci_tbl[i].device != PCI_ANY_ID
|
||||
&& asihpi_pci_tbl[i].device !=
|
||||
pci_info->pci_dev->device)
|
||||
continue;
|
||||
if (asihpi_pci_tbl[i].subvendor != PCI_ANY_ID
|
||||
&& asihpi_pci_tbl[i].subvendor !=
|
||||
pci_info->pci_dev->subsystem_vendor)
|
||||
continue;
|
||||
if (asihpi_pci_tbl[i].subdevice != PCI_ANY_ID
|
||||
&& asihpi_pci_tbl[i].subdevice !=
|
||||
pci_info->pci_dev->subsystem_device)
|
||||
continue;
|
||||
|
||||
/* HPI_DEBUG_LOG(DEBUG, " %x,%lx\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)
|
||||
{
|
||||
if ((phm->adapter_index < HPI_MAX_ADAPTERS)
|
||||
&& hpi_entry_points[phm->adapter_index])
|
||||
hpi_entry_points[phm->adapter_index] (phm, phr);
|
||||
else
|
||||
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 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)
|
||||
{
|
||||
if (phm->adapter_index != HPI_ADAPTER_INDEX_INVALID)
|
||||
HPI_DEBUG_LOG(WARNING,
|
||||
"suspicious adapter index %d in subsys message 0x%x.\n",
|
||||
phm->adapter_index, phm->function);
|
||||
|
||||
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));
|
||||
/* 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);
|
||||
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
|
||||
HPI_SUBSYS_DRIVER_UNLOAD, 0);
|
||||
return;
|
||||
|
||||
case HPI_SUBSYS_GET_NUM_ADAPTERS:
|
||||
case HPI_SUBSYS_GET_ADAPTER:
|
||||
HPI_COMMON(phm, phr);
|
||||
break;
|
||||
|
||||
case HPI_SUBSYS_CREATE_ADAPTER:
|
||||
HPIMSGX__init(phm, phr);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Must explicitly handle every subsys message in this switch */
|
||||
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function,
|
||||
HPI_ERROR_INVALID_FUNC);
|
||||
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;
|
||||
case HPI_ADAPTER_DELETE:
|
||||
HPIMSGX__cleanup(phm->adapter_index, h_owner);
|
||||
{
|
||||
struct hpi_message hm;
|
||||
struct hpi_response hr;
|
||||
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);
|
||||
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_REQUEST) {
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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_unlock(&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_unlock(&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_unlock(&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_unlock(&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_unlock(&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_unlock(&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_unlock(&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_unlock(&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.ax.info.num_outstreams;
|
||||
aDAPTER_INFO[adapter].num_instreams = hr.u.ax.info.num_instreams;
|
||||
aDAPTER_INFO[adapter].type = hr.u.ax.info.adapter_type;
|
||||
|
||||
/* 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 0;
|
||||
}
|
||||
|
||||
static void HPIMSGX__reset(u16 adapter_index)
|
||||
{
|
||||
int i;
|
||||
u16 adapter;
|
||||
struct hpi_response hr;
|
||||
|
||||
if (adapter_index == HPIMSGX_ALLADAPTERS) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* Init response here so we can pass in previous adapter list */
|
||||
hpi_init_response(&hr, phm->object, phm->function,
|
||||
HPI_ERROR_INVALID_OBJ);
|
||||
|
||||
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 successfully
|
||||
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-2011 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_ */
|
480
sound/pci/asihpi/hpioctl.c
Normal file
480
sound/pci/asihpi/hpioctl.c
Normal file
|
@ -0,0 +1,480 @@
|
|||
/*******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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 "hpi_version.h"
|
||||
#include "hpimsginit.h"
|
||||
#include "hpidebug.h"
|
||||
#include "hpimsgx.h"
|
||||
#include "hpioctl.h"
|
||||
#include "hpicmn.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/module.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)
|
||||
{
|
||||
if ((phm->adapter_index >= HPI_MAX_ADAPTERS)
|
||||
&& (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;
|
||||
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. */
|
||||
if (get_user(puhm, &phpi_ioctl_data->phm)
|
||||
|| get_user(puhr, &phpi_ioctl_data->phr)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Now read the message size and data from user space. */
|
||||
if (get_user(hm->h.size, (u16 __user *)puhm)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (get_user(res_max_size, (u16 __user *)puhr)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
switch (hm->h.function) {
|
||||
case HPI_SUBSYS_CREATE_ADAPTER:
|
||||
case HPI_ADAPTER_DELETE:
|
||||
/* 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;
|
||||
}
|
||||
|
||||
hr->h.size = res_max_size;
|
||||
if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
|
||||
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;
|
||||
struct hpi_adapter *pa = NULL;
|
||||
|
||||
if (hm->h.adapter_index < ARRAY_SIZE(adapters))
|
||||
pa = &adapters[hm->h.adapter_index];
|
||||
|
||||
if (!pa || !pa->adapter || !pa->adapter->type) {
|
||||
hpi_init_response(&hr->r0, hm->h.object,
|
||||
hm->h.function, 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(&pa->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(&pa->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(&pa->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);
|
||||
hr->h.error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
|
||||
hr->h.specific_error = hr->h.size;
|
||||
hr->h.size = sizeof(hr->h);
|
||||
}
|
||||
|
||||
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 asihpi_adapter_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
int idx, nm;
|
||||
int adapter_index;
|
||||
unsigned int memlen;
|
||||
struct hpi_message hm;
|
||||
struct hpi_response hr;
|
||||
struct hpi_adapter adapter;
|
||||
struct hpi_pci pci;
|
||||
|
||||
memset(&adapter, 0, sizeof(adapter));
|
||||
|
||||
dev_printk(KERN_DEBUG, &pci_dev->dev,
|
||||
"probe %04x:%04x,%04x:%04x,%04x\n", pci_dev->vendor,
|
||||
pci_dev->device, pci_dev->subsystem_vendor,
|
||||
pci_dev->subsystem_device, pci_dev->devfn);
|
||||
|
||||
if (pci_enable_device(pci_dev) < 0) {
|
||||
dev_err(&pci_dev->dev,
|
||||
"pci_enable_device failed, disabling device\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pci_set_master(pci_dev); /* also sets latency timer if < 16 */
|
||||
|
||||
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 = HPI_ADAPTER_INDEX_INVALID;
|
||||
|
||||
nm = HPI_MAX_ADAPTER_MEM_SPACES;
|
||||
|
||||
for (idx = 0; idx < nm; idx++) {
|
||||
HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx,
|
||||
&pci_dev->resource[idx]);
|
||||
|
||||
if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
|
||||
memlen = pci_resource_len(pci_dev, idx);
|
||||
pci.ap_mem_base[idx] =
|
||||
ioremap(pci_resource_start(pci_dev, idx),
|
||||
memlen);
|
||||
if (!pci.ap_mem_base[idx]) {
|
||||
HPI_DEBUG_LOG(ERROR,
|
||||
"ioremap failed, aborting\n");
|
||||
/* unmap previously mapped pci mem space */
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pci.pci_dev = 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;
|
||||
|
||||
adapter_index = hr.u.s.adapter_index;
|
||||
adapter.adapter = hpi_find_adapter(adapter_index);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
|
||||
HPI_ADAPTER_OPEN);
|
||||
hm.adapter_index = adapter.adapter->index;
|
||||
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
|
||||
|
||||
if (hr.error)
|
||||
goto err;
|
||||
|
||||
/* WARNING can't init mutex in 'adapter'
|
||||
* and then copy it to adapters[] ?!?!
|
||||
*/
|
||||
adapters[adapter_index] = adapter;
|
||||
mutex_init(&adapters[adapter_index].mutex);
|
||||
pci_set_drvdata(pci_dev, &adapters[adapter_index]);
|
||||
|
||||
dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n",
|
||||
adapter.adapter->type, adapter_index);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
|
||||
if (pci.ap_mem_base[idx]) {
|
||||
iounmap(pci.ap_mem_base[idx]);
|
||||
pci.ap_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 asihpi_adapter_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
int idx;
|
||||
struct hpi_message hm;
|
||||
struct hpi_response hr;
|
||||
struct hpi_adapter *pa;
|
||||
struct hpi_pci pci;
|
||||
|
||||
pa = pci_get_drvdata(pci_dev);
|
||||
pci = pa->adapter->pci;
|
||||
|
||||
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
|
||||
HPI_ADAPTER_DELETE);
|
||||
hm.adapter_index = pa->adapter->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 (pci.ap_mem_base[idx])
|
||||
iounmap(pci.ap_mem_base[idx]);
|
||||
}
|
||||
|
||||
if (pa->p_buffer)
|
||||
vfree(pa->p_buffer);
|
||||
|
||||
if (1)
|
||||
dev_info(&pci_dev->dev,
|
||||
"remove %04x:%04x,%04x:%04x,%04x, HPI index %d\n",
|
||||
pci_dev->vendor, pci_dev->device,
|
||||
pci_dev->subsystem_vendor, pci_dev->subsystem_device,
|
||||
pci_dev->devfn, pa->adapter->index);
|
||||
|
||||
memset(pa, 0, sizeof(*pa));
|
||||
}
|
||||
|
||||
void __init asihpi_init(void)
|
||||
{
|
||||
struct hpi_message hm;
|
||||
struct hpi_response hr;
|
||||
|
||||
memset(adapters, 0, sizeof(adapters));
|
||||
|
||||
printk(KERN_INFO "ASIHPI driver " HPI_VER_STRING "\n");
|
||||
|
||||
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-2011 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 asihpi_adapter_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *pci_id);
|
||||
void 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)
|
83
sound/pci/asihpi/hpios.c
Normal file
83
sound/pci/asihpi/hpios.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2012 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);
|
||||
|
||||
}
|
||||
|
||||
/** Allocate an area of locked memory for bus master DMA operations.
|
||||
|
||||
If allocation fails, return 1, 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 1;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
165
sound/pci/asihpi/hpios.h
Normal file
165
sound/pci/asihpi/hpios.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
/******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2011 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_BUILD_KERNEL_MODE
|
||||
|
||||
#include <linux/io.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>
|
||||
#include <linux/mutex.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_unlock(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_BUILD_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_unlock(obj) spin_unlock(&((obj)->list_lock.lock))
|
||||
|
||||
struct snd_card;
|
||||
|
||||
/** pci drvdata points to an instance of this struct */
|
||||
struct hpi_adapter {
|
||||
struct hpi_adapter_obj *adapter;
|
||||
struct snd_card *snd_card;
|
||||
|
||||
/* mutex prevents contention for one card
|
||||
between multiple user programs (via ioctl) */
|
||||
struct mutex mutex;
|
||||
char *p_buffer;
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
#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-2011 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…
Add table
Add a link
Reference in a new issue