2019-05-29 17:18:09 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-04-21 20:17:39 +04:00
/*******************************************************************************
AudioScience HPI driver
2014-11-20 06:22:53 +03:00
Common Linux HPI ioctl and module probe / remove functions
Copyright ( C ) 1997 - 2014 AudioScience Inc . < support @ audioscience . com >
2010-04-21 20:17:39 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define SOURCEFILE_NAME "hpioctl.c"
# include "hpi_internal.h"
2011-12-22 04:38:31 +04:00
# include "hpi_version.h"
2010-04-21 20:17:39 +04:00
# include "hpimsginit.h"
# include "hpidebug.h"
# include "hpimsgx.h"
# include "hpioctl.h"
2011-04-05 12:55:47 +04:00
# include "hpicmn.h"
2010-04-21 20:17:39 +04:00
# include <linux/fs.h>
2014-11-20 06:22:53 +03:00
# include <linux/interrupt.h>
2010-04-21 20:17:39 +04:00
# include <linux/slab.h>
# include <linux/moduleparam.h>
2015-01-28 19:24:43 +03:00
# include <linux/uaccess.h>
2011-02-10 07:25:58 +03:00
# include <linux/pci.h>
2010-04-21 20:17:39 +04:00
# include <linux/stringify.h>
2011-07-15 20:38:28 +04:00
# include <linux/module.h>
2015-06-02 12:01:38 +03:00
# include <linux/vmalloc.h>
2018-04-24 09:01:48 +03:00
# include <linux/nospec.h>
2010-04-21 20:17:39 +04:00
# 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 ;
2018-05-23 22:20:59 +03:00
module_param ( prealloc_stream_buf , int , 0444 ) ;
2010-04-21 20:17:39 +04:00
MODULE_PARM_DESC ( prealloc_stream_buf ,
2011-02-10 07:25:58 +03:00
" Preallocate size for per-adapter stream buffer " ) ;
2010-04-21 20:17:39 +04:00
/* Allow the debug level to be changed after module load.
E . g . echo 2 > / sys / module / asihpi / parameters / hpiDebugLevel
*/
2018-05-23 22:20:59 +03:00
module_param ( hpi_debug_level , int , 0644 ) ;
2010-04-21 20:17:39 +04:00
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 )
{
2011-12-22 04:38:43 +04:00
if ( ( phm - > adapter_index > = HPI_MAX_ADAPTERS )
2010-04-21 20:17:39 +04:00
& & ( 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 ;
2017-09-19 08:21:56 +03:00
u16 msg_size ;
2010-04-21 20:17:39 +04:00
u16 res_max_size ;
u32 uncopied_bytes ;
int err = 0 ;
if ( cmd ! = HPI_IOCTL_LINUX )
return - EINVAL ;
hm = kmalloc ( sizeof ( * hm ) , GFP_KERNEL ) ;
2016-10-13 15:36:41 +03:00
hr = kzalloc ( sizeof ( * hr ) , GFP_KERNEL ) ;
2010-04-21 20:17:39 +04:00
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. */
2011-02-10 07:25:58 +03:00
if ( get_user ( puhm , & phpi_ioctl_data - > phm )
| | get_user ( puhr , & phpi_ioctl_data - > phr ) ) {
2010-07-28 20:41:56 +04:00
err = - EFAULT ;
goto out ;
}
2010-04-21 20:17:39 +04:00
/* Now read the message size and data from user space. */
2017-09-19 08:21:56 +03:00
if ( get_user ( msg_size , ( u16 __user * ) puhm ) ) {
2010-07-28 20:41:56 +04:00
err = - EFAULT ;
goto out ;
}
2017-09-19 08:21:56 +03:00
if ( msg_size > sizeof ( * hm ) )
msg_size = sizeof ( * hm ) ;
2010-04-21 20:17:39 +04:00
2011-02-10 07:25:58 +03:00
/* printk(KERN_INFO "message size %d\n", hm->h.wSize); */
2010-04-21 20:17:39 +04:00
2017-09-19 08:21:56 +03:00
uncopied_bytes = copy_from_user ( hm , puhm , msg_size ) ;
2010-04-21 20:17:39 +04:00
if ( uncopied_bytes ) {
HPI_DEBUG_LOG ( ERROR , " uncopied bytes %d \n " , uncopied_bytes ) ;
err = - EFAULT ;
goto out ;
}
2017-09-19 08:21:56 +03:00
/* Override h.size in case it is changed between two userspace fetches */
hm - > h . size = msg_size ;
2010-07-28 20:41:56 +04:00
if ( get_user ( res_max_size , ( u16 __user * ) puhr ) ) {
err = - EFAULT ;
goto out ;
}
2010-04-21 20:17:39 +04:00
/* 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 ;
}
2014-12-31 13:48:32 +03:00
res_max_size = min_t ( size_t , res_max_size , sizeof ( * hr ) ) ;
2011-04-05 12:55:47 +04:00
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 ;
}
2011-02-10 07:25:58 +03:00
hr - > h . size = res_max_size ;
2010-04-21 20:17:39 +04:00
if ( hm - > h . object = = HPI_OBJ_SUBSYSTEM ) {
2011-04-05 12:55:47 +04:00
hpi_send_recv_f ( & hm - > m0 , & hr - > r0 , file ) ;
2010-04-21 20:17:39 +04:00
} else {
u16 __user * ptr = NULL ;
u32 size = 0 ;
/* -1=no data 0=read from user mem, 1=write to user mem */
int wrflag = - 1 ;
2011-12-22 04:38:43 +04:00
struct hpi_adapter * pa = NULL ;
2011-08-02 01:44:24 +04:00
2011-12-22 04:38:43 +04:00
if ( hm - > h . adapter_index < ARRAY_SIZE ( adapters ) )
2018-04-24 09:01:48 +03:00
pa = & adapters [ array_index_nospec ( hm - > h . adapter_index ,
ARRAY_SIZE ( adapters ) ) ] ;
2010-04-21 20:17:39 +04:00
2011-12-22 04:38:43 +04:00
if ( ! pa | | ! pa - > adapter | | ! pa - > adapter - > type ) {
2011-08-02 01:44:24 +04:00
hpi_init_response ( & hr - > r0 , hm - > h . object ,
hm - > h . function , HPI_ERROR_BAD_ADAPTER_NUMBER ) ;
2010-04-21 20:17:39 +04:00
uncopied_bytes =
copy_to_user ( puhr , hr , sizeof ( hr - > h ) ) ;
if ( uncopied_bytes )
err = - EFAULT ;
else
err = 0 ;
goto out ;
}
2011-07-27 12:03:51 +04:00
if ( mutex_lock_interruptible ( & pa - > mutex ) ) {
2010-04-21 20:17:39 +04:00
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 ,
2011-02-10 07:25:58 +03:00
" Realloc adapter %d stream "
2010-04-21 20:17:39 +04:00
" 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 ) ;
2011-07-27 12:03:51 +04:00
mutex_unlock ( & pa - > mutex ) ;
2010-04-21 20:17:39 +04:00
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 ,
2011-02-10 07:25:58 +03:00
" Missed %d of %d "
2010-04-21 20:17:39 +04:00
" 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 ,
2011-02-10 07:25:58 +03:00
" Missed %d of %d " " bytes to user \n " ,
2010-04-21 20:17:39 +04:00
uncopied_bytes , size ) ;
}
2011-07-27 12:03:51 +04:00
mutex_unlock ( & pa - > mutex ) ;
2010-04-21 20:17:39 +04:00
}
/* 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 ) ;
2011-02-10 07:25:58 +03:00
hr - > h . error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL ;
hr - > h . specific_error = hr - > h . size ;
hr - > h . size = sizeof ( hr - > h ) ;
2010-04-21 20:17:39 +04:00
}
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 ;
}
2014-11-20 06:22:53 +03:00
static int asihpi_irq_count ;
static irqreturn_t asihpi_isr ( int irq , void * dev_id )
{
struct hpi_adapter * a = dev_id ;
int handled ;
if ( ! a - > adapter - > irq_query_and_clear ) {
pr_err ( " asihpi_isr ASI%04X:%d no handler \n " , a - > adapter - > type ,
a - > adapter - > index ) ;
return IRQ_NONE ;
}
handled = a - > adapter - > irq_query_and_clear ( a - > adapter , 0 ) ;
if ( ! handled )
return IRQ_NONE ;
asihpi_irq_count + + ;
/* printk(KERN_INFO "asihpi_isr %d ASI%04X:%d irq handled\n",
asihpi_irq_count , a - > adapter - > type , a - > adapter - > index ) ; */
if ( a - > interrupt_callback )
a - > interrupt_callback ( a ) ;
return IRQ_HANDLED ;
}
2012-12-06 21:35:10 +04:00
int asihpi_adapter_probe ( struct pci_dev * pci_dev ,
const struct pci_device_id * pci_id )
2010-04-21 20:17:39 +04:00
{
2014-11-20 06:22:53 +03:00
int idx , nm , low_latency_mode = 0 , irq_supported = 0 ;
2011-12-22 04:38:43 +04:00
int adapter_index ;
2010-04-21 20:17:39 +04:00
unsigned int memlen ;
struct hpi_message hm ;
struct hpi_response hr ;
struct hpi_adapter adapter ;
struct hpi_pci pci ;
memset ( & adapter , 0 , sizeof ( adapter ) ) ;
2011-02-10 07:25:58 +03:00
dev_printk ( KERN_DEBUG , & pci_dev - > dev ,
" probe %04x:%04x,%04x:%04x,%04x \n " , pci_dev - > vendor ,
pci_dev - > device , pci_dev - > subsystem_vendor ,
2010-04-21 20:17:39 +04:00
pci_dev - > subsystem_device , pci_dev - > devfn ) ;
2011-02-10 07:25:58 +03:00
if ( pci_enable_device ( pci_dev ) < 0 ) {
2012-10-28 12:05:54 +04:00
dev_err ( & pci_dev - > dev ,
2011-02-10 07:25:58 +03:00
" pci_enable_device failed, disabling device \n " ) ;
return - EIO ;
}
pci_set_master ( pci_dev ) ; /* also sets latency timer if < 16 */
2010-04-21 20:17:39 +04:00
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 ) ;
2011-02-10 07:25:58 +03:00
hm . adapter_index = HPI_ADAPTER_INDEX_INVALID ;
2010-04-21 20:17:39 +04:00
nm = HPI_MAX_ADAPTER_MEM_SPACES ;
for ( idx = 0 ; idx < nm ; idx + + ) {
2011-04-05 12:55:48 +04:00
HPI_DEBUG_LOG ( INFO , " resource %d %pR \n " , idx ,
& pci_dev - > resource [ idx ] ) ;
2010-04-21 20:17:39 +04:00
if ( pci_resource_flags ( pci_dev , idx ) & IORESOURCE_MEM ) {
memlen = pci_resource_len ( pci_dev , idx ) ;
2011-12-22 04:38:43 +04:00
pci . ap_mem_base [ idx ] =
2010-04-21 20:17:39 +04:00
ioremap ( pci_resource_start ( pci_dev , idx ) ,
memlen ) ;
2011-12-22 04:38:43 +04:00
if ( ! pci . ap_mem_base [ idx ] ) {
2010-04-21 20:17:39 +04:00
HPI_DEBUG_LOG ( ERROR ,
" ioremap failed, aborting \n " ) ;
/* unmap previously mapped pci mem space */
goto err ;
}
}
}
2011-02-10 07:25:58 +03:00
pci . pci_dev = pci_dev ;
2010-04-21 20:17:39 +04:00
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 ;
2011-12-22 04:38:43 +04:00
adapter_index = hr . u . s . adapter_index ;
adapter . adapter = hpi_find_adapter ( adapter_index ) ;
2010-04-21 20:17:39 +04:00
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 ;
}
}
2011-04-05 12:55:47 +04:00
hpi_init_message_response ( & hm , & hr , HPI_OBJ_ADAPTER ,
HPI_ADAPTER_OPEN ) ;
2011-12-22 04:38:43 +04:00
hm . adapter_index = adapter . adapter - > index ;
2011-04-05 12:55:47 +04:00
hpi_send_recv_ex ( & hm , & hr , HOWNER_KERNEL ) ;
2010-04-21 20:17:39 +04:00
2014-11-20 06:22:53 +03:00
if ( hr . error ) {
HPI_DEBUG_LOG ( ERROR , " HPI_ADAPTER_OPEN failed, aborting \n " ) ;
goto err ;
}
/* Check if current mode == Low Latency mode */
hpi_init_message_response ( & hm , & hr , HPI_OBJ_ADAPTER ,
HPI_ADAPTER_GET_MODE ) ;
hm . adapter_index = adapter . adapter - > index ;
hpi_send_recv_ex ( & hm , & hr , HOWNER_KERNEL ) ;
2014-11-20 06:22:56 +03:00
if ( ! hr . error
& & hr . u . ax . mode . adapter_mode = = HPI_ADAPTER_MODE_LOW_LATENCY )
2014-11-20 06:22:53 +03:00
low_latency_mode = 1 ;
2014-11-20 06:22:56 +03:00
else
dev_info ( & pci_dev - > dev ,
" Adapter at index %d is not in low latency mode \n " ,
adapter . adapter - > index ) ;
2014-11-20 06:22:53 +03:00
/* Check if IRQs are supported */
hpi_init_message_response ( & hm , & hr , HPI_OBJ_ADAPTER ,
HPI_ADAPTER_GET_PROPERTY ) ;
hm . adapter_index = adapter . adapter - > index ;
hm . u . ax . property_set . property = HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ ;
hpi_send_recv_ex ( & hm , & hr , HOWNER_KERNEL ) ;
if ( hr . error | | ! hr . u . ax . property_get . parameter1 ) {
dev_info ( & pci_dev - > dev ,
" IRQs not supported by adapter at index %d \n " ,
adapter . adapter - > index ) ;
} else {
irq_supported = 1 ;
}
2010-04-21 20:17:39 +04:00
/* WARNING can't init mutex in 'adapter'
* and then copy it to adapters [ ] ? ! ? !
*/
2011-12-22 04:38:43 +04:00
adapters [ adapter_index ] = adapter ;
mutex_init ( & adapters [ adapter_index ] . mutex ) ;
pci_set_drvdata ( pci_dev , & adapters [ adapter_index ] ) ;
2010-04-21 20:17:39 +04:00
2014-11-20 06:22:53 +03:00
if ( low_latency_mode & & irq_supported ) {
if ( ! adapter . adapter - > irq_query_and_clear ) {
dev_err ( & pci_dev - > dev ,
" no IRQ handler for adapter %d, aborting \n " ,
adapter . adapter - > index ) ;
goto err ;
}
/* Disable IRQ generation on DSP side by setting the rate to 0 */
hpi_init_message_response ( & hm , & hr , HPI_OBJ_ADAPTER ,
HPI_ADAPTER_SET_PROPERTY ) ;
hm . adapter_index = adapter . adapter - > index ;
hm . u . ax . property_set . property = HPI_ADAPTER_PROPERTY_IRQ_RATE ;
hm . u . ax . property_set . parameter1 = 0 ;
hm . u . ax . property_set . parameter2 = 0 ;
hpi_send_recv_ex ( & hm , & hr , HOWNER_KERNEL ) ;
if ( hr . error ) {
HPI_DEBUG_LOG ( ERROR ,
" HPI_ADAPTER_GET_MODE failed, aborting \n " ) ;
goto err ;
}
/* Note: request_irq calls asihpi_isr here */
if ( request_irq ( pci_dev - > irq , asihpi_isr , IRQF_SHARED ,
" asihpi " , & adapters [ adapter_index ] ) ) {
dev_err ( & pci_dev - > dev , " request_irq(%d) failed \n " ,
pci_dev - > irq ) ;
goto err ;
}
adapters [ adapter_index ] . interrupt_mode = 1 ;
dev_info ( & pci_dev - > dev , " using irq %d \n " , pci_dev - > irq ) ;
adapters [ adapter_index ] . irq = pci_dev - > irq ;
} else {
dev_info ( & pci_dev - > dev , " using polled mode \n " ) ;
}
2012-10-28 12:05:54 +04:00
dev_info ( & pci_dev - > dev , " probe succeeded for ASI%04X HPI index %d \n " ,
adapter . adapter - > type , adapter_index ) ;
2010-04-21 20:17:39 +04:00
return 0 ;
err :
for ( idx = 0 ; idx < HPI_MAX_ADAPTER_MEM_SPACES ; idx + + ) {
2011-12-22 04:38:43 +04:00
if ( pci . ap_mem_base [ idx ] ) {
iounmap ( pci . ap_mem_base [ idx ] ) ;
pci . ap_mem_base [ idx ] = NULL ;
2010-04-21 20:17:39 +04:00
}
}
if ( adapter . p_buffer ) {
adapter . buffer_size = 0 ;
vfree ( adapter . p_buffer ) ;
}
HPI_DEBUG_LOG ( ERROR , " adapter_probe failed \n " ) ;
return - ENODEV ;
}
2012-12-06 21:35:10 +04:00
void asihpi_adapter_remove ( struct pci_dev * pci_dev )
2010-04-21 20:17:39 +04:00
{
int idx ;
struct hpi_message hm ;
struct hpi_response hr ;
struct hpi_adapter * pa ;
2011-12-22 04:38:43 +04:00
struct hpi_pci pci ;
2010-11-15 23:14:02 +03:00
pa = pci_get_drvdata ( pci_dev ) ;
2011-12-22 04:38:43 +04:00
pci = pa - > adapter - > pci ;
2010-04-21 20:17:39 +04:00
2014-11-20 06:22:53 +03:00
/* Disable IRQ generation on DSP side */
hpi_init_message_response ( & hm , & hr , HPI_OBJ_ADAPTER ,
HPI_ADAPTER_SET_PROPERTY ) ;
hm . adapter_index = pa - > adapter - > index ;
hm . u . ax . property_set . property = HPI_ADAPTER_PROPERTY_IRQ_RATE ;
hm . u . ax . property_set . parameter1 = 0 ;
hm . u . ax . property_set . parameter2 = 0 ;
hpi_send_recv_ex ( & hm , & hr , HOWNER_KERNEL ) ;
2011-04-05 12:55:47 +04:00
hpi_init_message_response ( & hm , & hr , HPI_OBJ_ADAPTER ,
HPI_ADAPTER_DELETE ) ;
2011-12-22 04:38:43 +04:00
hm . adapter_index = pa - > adapter - > index ;
2010-04-21 20:17:39 +04:00
hpi_send_recv_ex ( & hm , & hr , HOWNER_KERNEL ) ;
/* unmap PCI memory space, mapped during device init. */
2015-01-04 00:55:54 +03:00
for ( idx = 0 ; idx < HPI_MAX_ADAPTER_MEM_SPACES ; + + idx )
iounmap ( pci . ap_mem_base [ idx ] ) ;
2010-04-21 20:17:39 +04:00
2014-11-20 06:22:53 +03:00
if ( pa - > irq )
free_irq ( pa - > irq , pa ) ;
2014-12-02 20:05:32 +03:00
vfree ( pa - > p_buffer ) ;
2010-04-21 20:17:39 +04:00
2011-02-10 07:25:58 +03:00
if ( 1 )
2012-10-28 12:05:54 +04:00
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 ) ;
2011-02-10 07:26:18 +03:00
memset ( pa , 0 , sizeof ( * pa ) ) ;
2010-04-21 20:17:39 +04:00
}
void __init asihpi_init ( void )
{
struct hpi_message hm ;
struct hpi_response hr ;
memset ( adapters , 0 , sizeof ( adapters ) ) ;
2010-07-06 00:37:07 +04:00
printk ( KERN_INFO " ASIHPI driver " HPI_VER_STRING " \n " ) ;
2010-04-21 20:17:39 +04:00
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 ) ;
}