2012-11-01 21:17:15 +02:00
/*
*
* Intel Management Engine Interface ( Intel MEI ) Linux driver
* Copyright ( c ) 2003 - 2012 , Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope 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 .
*
*/
# include <linux/kernel.h>
# include <linux/fs.h>
# include <linux/errno.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/ioctl.h>
# include <linux/cdev.h>
# include <linux/list.h>
# include <linux/delay.h>
# include <linux/sched.h>
# include <linux/uuid.h>
# include <linux/jiffies.h>
# include <linux/uaccess.h>
2014-09-29 16:31:46 +03:00
# include <linux/slab.h>
2012-11-01 21:17:15 +02:00
2012-12-25 19:06:03 +02:00
# include <linux/mei.h>
2012-11-01 21:17:15 +02:00
# include "mei_dev.h"
2013-01-08 23:07:12 +02:00
# include "hbm.h"
2013-01-08 23:07:14 +02:00
# include "client.h"
2012-11-01 21:17:15 +02:00
2013-01-08 23:07:21 +02:00
const uuid_le mei_amthif_guid = UUID_LE ( 0x12f80028 , 0xb4b7 , 0x4b2d ,
0xac , 0xa8 , 0x46 , 0xe0 ,
0xff , 0x65 , 0x81 , 0x4c ) ;
2012-11-01 21:17:15 +02:00
/**
* mei_amthif_reset_params - initializes mei device iamthif
*
* @ dev : the device structure
*/
void mei_amthif_reset_params ( struct mei_device * dev )
{
/* reset iamthif parameters. */
dev - > iamthif_current_cb = NULL ;
dev - > iamthif_canceled = false ;
dev - > iamthif_state = MEI_IAMTHIF_IDLE ;
dev - > iamthif_timer = 0 ;
2013-09-02 13:29:47 +03:00
dev - > iamthif_stall_timer = 0 ;
2013-09-16 23:44:47 +03:00
dev - > iamthif_open_count = 0 ;
2012-11-01 21:17:15 +02:00
}
/**
2013-04-05 01:05:05 +09:00
* mei_amthif_host_init - mei initialization amthif client .
2012-11-01 21:17:15 +02:00
*
* @ dev : the device structure
*
2014-09-29 16:31:50 +03:00
* Return : 0 on success , < 0 on failure .
2012-11-01 21:17:15 +02:00
*/
2013-01-08 23:07:22 +02:00
int mei_amthif_host_init ( struct mei_device * dev )
2012-11-01 21:17:15 +02:00
{
2013-01-08 23:07:22 +02:00
struct mei_cl * cl = & dev - > iamthif_cl ;
2014-08-24 12:08:55 +03:00
struct mei_me_client * me_cl ;
int ret ;
2012-11-01 21:17:15 +02:00
2013-01-08 23:07:23 +02:00
dev - > iamthif_state = MEI_IAMTHIF_IDLE ;
2013-01-08 23:07:22 +02:00
mei_cl_init ( cl , dev ) ;
2012-11-01 21:17:15 +02:00
2014-08-24 12:08:55 +03:00
me_cl = mei_me_cl_by_uuid ( dev , & mei_amthif_guid ) ;
if ( ! me_cl ) {
2014-09-29 16:31:42 +03:00
dev_info ( dev - > dev , " amthif: failed to find the client " ) ;
2014-02-19 17:35:49 +02:00
return - ENOTTY ;
2012-11-01 21:17:15 +02:00
}
2014-08-24 12:08:55 +03:00
cl - > me_client_id = me_cl - > client_id ;
2014-08-21 14:29:15 +03:00
cl - > cl_uuid = me_cl - > props . protocol_name ;
2013-01-08 23:07:22 +02:00
2012-11-01 21:17:15 +02:00
/* Assign iamthif_mtu to the value received from ME */
2014-08-24 12:08:55 +03:00
dev - > iamthif_mtu = me_cl - > props . max_msg_length ;
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " IAMTHIF_MTU = %d \n " , dev - > iamthif_mtu ) ;
2012-11-01 21:17:15 +02:00
2013-01-08 23:07:22 +02:00
ret = mei_cl_link ( cl , MEI_IAMTHIF_HOST_CLIENT_ID ) ;
if ( ret < 0 ) {
2015-01-11 00:07:16 +02:00
dev_err ( dev - > dev , " amthif: failed cl_link %d \n " , ret ) ;
goto out ;
2013-01-08 23:07:22 +02:00
}
2014-02-17 15:13:21 +02:00
ret = mei_cl_connect ( cl , NULL ) ;
dev - > iamthif_state = MEI_IAMTHIF_IDLE ;
2015-01-11 00:07:16 +02:00
out :
mei_me_cl_put ( me_cl ) ;
2014-02-17 15:13:21 +02:00
return ret ;
2012-11-01 21:17:15 +02:00
}
/**
* mei_amthif_find_read_list_entry - finds a amthilist entry for current file
*
* @ dev : the device structure
* @ file : pointer to file object
*
2014-09-29 16:31:49 +03:00
* Return : returned a list entry on success , NULL on failure .
2012-11-01 21:17:15 +02:00
*/
struct mei_cl_cb * mei_amthif_find_read_list_entry ( struct mei_device * dev ,
struct file * file )
{
2014-02-17 15:13:25 +02:00
struct mei_cl_cb * cb ;
2014-09-29 16:31:37 +03:00
2014-08-14 17:22:21 +03:00
list_for_each_entry ( cb , & dev - > amthif_rd_complete_list . list , list )
if ( cb - > file_object = = file )
2014-02-17 15:13:25 +02:00
return cb ;
2012-11-01 21:17:15 +02:00
return NULL ;
}
/**
* mei_amthif_read - read data from AMTHIF client
*
* @ dev : the device structure
* @ file : pointer to file object
2014-09-29 16:31:49 +03:00
* @ ubuf : pointer to user data in user space
2012-11-01 21:17:15 +02:00
* @ length : data length to read
* @ offset : data read offset
*
* Locking : called under " dev->device_lock " lock
*
2014-09-29 16:31:49 +03:00
* Return :
2012-11-01 21:17:15 +02:00
* returned data length on success ,
* zero if no data to read ,
* negative on failure .
*/
int mei_amthif_read ( struct mei_device * dev , struct file * file ,
char __user * ubuf , size_t length , loff_t * offset )
{
struct mei_cl * cl = file - > private_data ;
2014-08-24 12:08:55 +03:00
struct mei_cl_cb * cb ;
2012-11-01 21:17:15 +02:00
unsigned long timeout ;
2014-08-24 12:08:55 +03:00
int rets ;
int wait_ret ;
2012-11-01 21:17:15 +02:00
2014-01-08 22:31:46 +02:00
/* Only possible if we are in timeout */
2014-08-14 17:22:21 +03:00
if ( ! cl ) {
2014-09-29 16:31:42 +03:00
dev_err ( dev - > dev , " bad file ext. \n " ) ;
2014-02-19 17:35:49 +02:00
return - ETIME ;
2012-11-01 21:17:15 +02:00
}
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " checking amthif data \n " ) ;
2012-11-01 21:17:15 +02:00
cb = mei_amthif_find_read_list_entry ( dev , file ) ;
/* Check for if we can block or not*/
if ( cb = = NULL & & file - > f_flags & O_NONBLOCK )
return - EAGAIN ;
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " waiting for amthif data \n " ) ;
2012-11-01 21:17:15 +02:00
while ( cb = = NULL ) {
/* unlock the Mutex */
mutex_unlock ( & dev - > device_lock ) ;
wait_ret = wait_event_interruptible ( dev - > iamthif_cl . wait ,
( cb = mei_amthif_find_read_list_entry ( dev , file ) ) ) ;
2012-12-22 01:44:16 +04:00
/* Locking again the Mutex */
mutex_lock ( & dev - > device_lock ) ;
2012-11-01 21:17:15 +02:00
if ( wait_ret )
return - ERESTARTSYS ;
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " woke up from sleep \n " ) ;
2012-11-01 21:17:15 +02:00
}
2015-02-10 10:39:37 +02:00
if ( cb - > status ) {
rets = cb - > status ;
dev_dbg ( dev - > dev , " read operation failed %d \n " , rets ) ;
goto free ;
}
2012-11-01 21:17:15 +02:00
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " Got amthif data \n " ) ;
2012-11-01 21:17:15 +02:00
dev - > iamthif_timer = 0 ;
2015-02-10 10:39:37 +02:00
timeout = cb - > read_time +
mei_secs_to_jiffies ( MEI_IAMTHIF_READ_TIMER ) ;
dev_dbg ( dev - > dev , " amthif timeout = %lud \n " ,
timeout ) ;
if ( time_after ( jiffies , timeout ) ) {
dev_dbg ( dev - > dev , " amthif Time out \n " ) ;
/* 15 sec for the message has expired */
2015-02-10 10:39:45 +02:00
list_del_init ( & cb - > list ) ;
2015-02-10 10:39:37 +02:00
rets = - ETIME ;
goto free ;
2012-11-01 21:17:15 +02:00
}
/* if the whole message will fit remove it from the list */
if ( cb - > buf_idx > = * offset & & length > = ( cb - > buf_idx - * offset ) )
2015-02-10 10:39:45 +02:00
list_del_init ( & cb - > list ) ;
2012-11-01 21:17:15 +02:00
else if ( cb - > buf_idx > 0 & & cb - > buf_idx < = * offset ) {
/* end of the message has been reached */
2015-02-10 10:39:45 +02:00
list_del_init ( & cb - > list ) ;
2012-11-01 21:17:15 +02:00
rets = 0 ;
goto free ;
}
/* else means that not full buffer will be read and do not
* remove message from deletion list
*/
2015-02-10 10:39:42 +02:00
dev_dbg ( dev - > dev , " amthif cb->buf size - %d \n " ,
cb - > buf . size ) ;
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " amthif cb->buf_idx - %lu \n " , cb - > buf_idx ) ;
2012-11-01 21:17:15 +02:00
2014-01-08 22:31:46 +02:00
/* length is being truncated to PAGE_SIZE, however,
2012-11-01 21:17:15 +02:00
* the buf_idx may point beyond */
length = min_t ( size_t , length , ( cb - > buf_idx - * offset ) ) ;
2015-02-10 10:39:42 +02:00
if ( copy_to_user ( ubuf , cb - > buf . data + * offset , length ) ) {
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " failed to copy data to userland \n " ) ;
2012-11-01 21:17:15 +02:00
rets = - EFAULT ;
2014-03-16 14:35:57 +02:00
} else {
2012-11-01 21:17:15 +02:00
rets = length ;
if ( ( * offset + length ) < cb - > buf_idx ) {
* offset + = length ;
goto out ;
}
}
free :
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " free amthif cb memory. \n " ) ;
2012-11-01 21:17:15 +02:00
* offset = 0 ;
mei_io_cb_free ( cb ) ;
out :
return rets ;
}
/**
2015-02-10 10:39:39 +02:00
* mei_amthif_read_start - queue message for sending read credential
2012-11-01 21:17:15 +02:00
*
2015-02-10 10:39:39 +02:00
* @ cl : host client
* @ file : file pointer of message recipient
2012-11-01 21:17:15 +02:00
*
2014-09-29 16:31:49 +03:00
* Return : 0 on success , < 0 on failure .
2012-11-01 21:17:15 +02:00
*/
2015-02-10 10:39:39 +02:00
static int mei_amthif_read_start ( struct mei_cl * cl , struct file * file )
2012-11-01 21:17:15 +02:00
{
2015-02-10 10:39:39 +02:00
struct mei_device * dev = cl - > dev ;
struct mei_cl_cb * cb ;
size_t length = dev - > iamthif_mtu ;
int rets ;
2012-11-01 21:17:15 +02:00
2015-02-10 10:39:43 +02:00
cb = mei_io_cb_init ( cl , MEI_FOP_READ , file ) ;
2015-02-10 10:39:39 +02:00
if ( ! cb ) {
rets = - ENOMEM ;
goto err ;
}
2012-11-01 21:17:15 +02:00
2015-02-10 10:39:42 +02:00
rets = mei_io_cb_alloc_buf ( cb , length ) ;
2015-02-10 10:39:39 +02:00
if ( rets )
goto err ;
2012-11-01 21:17:15 +02:00
2015-02-10 10:39:39 +02:00
list_add_tail ( & cb - > list , & dev - > ctrl_wr_list . list ) ;
2012-11-01 21:17:15 +02:00
2015-02-10 10:39:39 +02:00
dev - > iamthif_state = MEI_IAMTHIF_READING ;
dev - > iamthif_file_object = cb - > file_object ;
dev - > iamthif_current_cb = cb ;
2012-11-01 21:17:15 +02:00
return 0 ;
2015-02-10 10:39:39 +02:00
err :
mei_io_cb_free ( cb ) ;
return rets ;
2012-11-01 21:17:15 +02:00
}
2012-11-01 21:17:18 +02:00
/**
* mei_amthif_send_cmd - send amthif command to the ME
*
2015-02-10 10:39:40 +02:00
* @ cl : the host client
2012-11-01 21:17:18 +02:00
* @ cb : mei call back struct
*
2014-09-29 16:31:49 +03:00
* Return : 0 on success , < 0 on failure .
2012-11-01 21:17:18 +02:00
*/
2015-02-10 10:39:40 +02:00
static int mei_amthif_send_cmd ( struct mei_cl * cl , struct mei_cl_cb * cb )
2012-11-01 21:17:18 +02:00
{
2015-02-10 10:39:40 +02:00
struct mei_device * dev ;
2012-11-01 21:17:18 +02:00
int ret ;
2015-02-10 10:39:40 +02:00
if ( ! cl - > dev | | ! cb )
2012-11-01 21:17:18 +02:00
return - ENODEV ;
2015-02-10 10:39:40 +02:00
dev = cl - > dev ;
2012-11-01 21:17:15 +02:00
dev - > iamthif_state = MEI_IAMTHIF_WRITING ;
dev - > iamthif_current_cb = cb ;
dev - > iamthif_file_object = cb - > file_object ;
dev - > iamthif_canceled = false ;
2015-02-10 10:39:40 +02:00
ret = mei_cl_write ( cl , cb , false ) ;
2012-11-01 21:17:15 +02:00
if ( ret < 0 )
2012-11-01 21:17:18 +02:00
return ret ;
2015-02-10 10:39:40 +02:00
if ( cb - > completed )
cb - > status = mei_amthif_read_start ( cl , cb - > file_object ) ;
2012-11-01 21:17:18 +02:00
2012-11-01 21:17:15 +02:00
return 0 ;
2012-11-01 21:17:18 +02:00
}
2012-11-01 21:17:15 +02:00
/**
2014-09-29 16:31:50 +03:00
* mei_amthif_run_next_cmd - send next amt command from queue
2012-11-01 21:17:15 +02:00
*
* @ dev : the device structure
2012-11-01 21:17:18 +02:00
*
2014-09-29 16:31:49 +03:00
* Return : 0 on success , < 0 on failure .
2012-11-01 21:17:15 +02:00
*/
2015-02-10 10:39:40 +02:00
int mei_amthif_run_next_cmd ( struct mei_device * dev )
2012-11-01 21:17:15 +02:00
{
2015-02-10 10:39:40 +02:00
struct mei_cl * cl = & dev - > iamthif_cl ;
2014-08-14 17:22:21 +03:00
struct mei_cl_cb * cb ;
2012-11-01 21:17:15 +02:00
dev - > iamthif_canceled = false ;
dev - > iamthif_state = MEI_IAMTHIF_IDLE ;
dev - > iamthif_timer = 0 ;
dev - > iamthif_file_object = NULL ;
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " complete amthif cmd_list cb. \n " ) ;
2012-11-01 21:17:15 +02:00
2014-10-02 13:39:31 +03:00
cb = list_first_entry_or_null ( & dev - > amthif_cmd_list . list ,
typeof ( * cb ) , list ) ;
if ( ! cb )
2015-02-10 10:39:40 +02:00
return 0 ;
2015-02-10 10:39:39 +02:00
list_del_init ( & cb - > list ) ;
2015-02-10 10:39:40 +02:00
return mei_amthif_send_cmd ( cl , cb ) ;
2012-11-01 21:17:15 +02:00
}
2015-02-10 10:39:40 +02:00
/**
* mei_amthif_write - write amthif data to amthif client
*
* @ cl : host client
* @ cb : mei call back struct
*
* Return : 0 on success , < 0 on failure .
*/
int mei_amthif_write ( struct mei_cl * cl , struct mei_cl_cb * cb )
{
struct mei_device * dev ;
if ( WARN_ON ( ! cl | | ! cl - > dev ) )
return - ENODEV ;
if ( WARN_ON ( ! cb ) )
return - EINVAL ;
dev = cl - > dev ;
list_add_tail ( & cb - > list , & dev - > amthif_cmd_list . list ) ;
return mei_amthif_run_next_cmd ( dev ) ;
}
2012-11-11 17:38:02 +02:00
2015-03-27 00:27:57 +02:00
/**
* mei_amthif_poll - the amthif poll function
*
* @ dev : the device structure
* @ file : pointer to file structure
* @ wait : pointer to poll_table structure
*
* Return : poll mask
*
* Locking : called under " dev->device_lock " lock
*/
2012-11-11 17:38:02 +02:00
unsigned int mei_amthif_poll ( struct mei_device * dev ,
struct file * file , poll_table * wait )
{
unsigned int mask = 0 ;
2013-07-25 20:15:53 +03:00
2012-11-11 17:38:02 +02:00
poll_wait ( file , & dev - > iamthif_cl . wait , wait ) ;
2013-07-25 20:15:53 +03:00
2015-03-27 00:27:57 +02:00
if ( dev - > iamthif_state = = MEI_IAMTHIF_READ_COMPLETE & &
dev - > iamthif_file_object = = file ) {
2013-07-25 20:15:53 +03:00
2015-03-27 00:27:57 +02:00
mask | = POLLIN | POLLRDNORM ;
2012-11-11 17:38:02 +02:00
mei_amthif_run_next_cmd ( dev ) ;
}
2013-07-25 20:15:53 +03:00
2012-11-11 17:38:02 +02:00
return mask ;
}
2012-11-01 21:17:15 +02:00
/**
2014-02-19 17:35:48 +02:00
* mei_amthif_irq_write - write iamthif command in irq thread context .
2012-11-01 21:17:15 +02:00
*
* @ cl : private data of the file object .
2014-09-29 16:31:49 +03:00
* @ cb : callback block .
2012-11-01 21:17:15 +02:00
* @ cmpl_list : complete list .
*
2014-09-29 16:31:49 +03:00
* Return : 0 , OK ; otherwise , error .
2012-11-01 21:17:15 +02:00
*/
2014-02-19 17:35:48 +02:00
int mei_amthif_irq_write ( struct mei_cl * cl , struct mei_cl_cb * cb ,
struct mei_cl_cb * cmpl_list )
2012-11-01 21:17:15 +02:00
{
2015-02-10 10:39:40 +02:00
int ret ;
2012-11-18 15:13:17 +02:00
2015-02-10 10:39:40 +02:00
ret = mei_cl_irq_write ( cl , cb , cmpl_list ) ;
if ( ret )
return ret ;
2012-11-01 21:17:15 +02:00
2015-02-10 10:39:40 +02:00
if ( cb - > completed )
2015-02-10 10:39:39 +02:00
cb - > status = mei_amthif_read_start ( cl , cb - > file_object ) ;
2012-11-18 15:13:17 +02:00
2012-11-01 21:17:15 +02:00
return 0 ;
}
/**
2014-09-29 16:31:50 +03:00
* mei_amthif_irq_read_msg - read routine after ISR to
2013-01-08 23:07:21 +02:00
* handle the read amthif message
2012-11-01 21:17:15 +02:00
*
2015-02-10 10:39:37 +02:00
* @ cl : mei client
2013-01-08 23:07:21 +02:00
* @ mei_hdr : header of amthif message
2015-02-10 10:39:41 +02:00
* @ cmpl_list : completed callbacks list
2012-11-01 21:17:15 +02:00
*
2015-02-10 10:39:41 +02:00
* Return : - ENODEV if cb is NULL 0 otherwise ; error message is in cb - > status
2012-11-01 21:17:15 +02:00
*/
2015-02-10 10:39:37 +02:00
int mei_amthif_irq_read_msg ( struct mei_cl * cl ,
2013-04-19 21:16:53 +03:00
struct mei_msg_hdr * mei_hdr ,
2015-02-10 10:39:41 +02:00
struct mei_cl_cb * cmpl_list )
2012-11-01 21:17:15 +02:00
{
2015-02-10 10:39:37 +02:00
struct mei_device * dev ;
2015-02-10 10:39:41 +02:00
int ret ;
2012-11-01 21:17:15 +02:00
2015-02-10 10:39:37 +02:00
dev = cl - > dev ;
2012-11-01 21:17:15 +02:00
2015-02-10 10:39:37 +02:00
if ( dev - > iamthif_state ! = MEI_IAMTHIF_READING )
2015-02-10 10:39:41 +02:00
return 0 ;
2012-11-01 21:17:15 +02:00
2015-02-10 10:39:41 +02:00
ret = mei_cl_irq_read_msg ( cl , mei_hdr , cmpl_list ) ;
if ( ret )
return ret ;
2012-11-01 21:17:15 +02:00
if ( ! mei_hdr - > msg_complete )
return 0 ;
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " completed amthif read. \n " ) ;
2012-11-01 21:17:15 +02:00
dev - > iamthif_current_cb = NULL ;
dev - > iamthif_stall_timer = 0 ;
return 0 ;
}
/**
* mei_amthif_complete - complete amthif callback .
*
* @ dev : the device structure .
2014-09-29 16:31:49 +03:00
* @ cb : callback block .
2012-11-01 21:17:15 +02:00
*/
void mei_amthif_complete ( struct mei_device * dev , struct mei_cl_cb * cb )
{
2015-02-10 10:39:39 +02:00
if ( cb - > fop_type = = MEI_FOP_WRITE ) {
if ( ! cb - > status ) {
dev - > iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER ;
mei_io_cb_free ( cb ) ;
return ;
}
/*
* in case of error enqueue the write cb to complete read list
* so it can be propagated to the reader
*/
list_add_tail ( & cb - > list , & dev - > amthif_rd_complete_list . list ) ;
wake_up_interruptible ( & dev - > iamthif_cl . wait ) ;
return ;
}
2012-11-01 21:17:15 +02:00
if ( dev - > iamthif_canceled ! = 1 ) {
dev - > iamthif_state = MEI_IAMTHIF_READ_COMPLETE ;
dev - > iamthif_stall_timer = 0 ;
2012-11-11 17:37:58 +02:00
list_add_tail ( & cb - > list , & dev - > amthif_rd_complete_list . list ) ;
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " amthif read completed \n " ) ;
2012-11-01 21:17:15 +02:00
dev - > iamthif_timer = jiffies ;
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " dev->iamthif_timer = %ld \n " ,
2015-02-10 10:39:39 +02:00
dev - > iamthif_timer ) ;
2012-11-01 21:17:15 +02:00
} else {
mei_amthif_run_next_cmd ( dev ) ;
}
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " completing amthif call back. \n " ) ;
2012-11-01 21:17:15 +02:00
wake_up_interruptible ( & dev - > iamthif_cl . wait ) ;
}
2012-11-11 17:38:01 +02:00
/**
* mei_clear_list - removes all callbacks associated with file
* from mei_cb_list
*
* @ dev : device structure .
* @ file : file structure
* @ mei_cb_list : callbacks list
*
* mei_clear_list is called to clear resources associated with file
* when application calls close function or Ctrl - C was pressed
*
2014-09-29 16:31:49 +03:00
* Return : true if callback removed from the list , false otherwise
2012-11-11 17:38:01 +02:00
*/
static bool mei_clear_list ( struct mei_device * dev ,
const struct file * file , struct list_head * mei_cb_list )
{
2015-02-10 10:39:45 +02:00
struct mei_cl * cl = & dev - > iamthif_cl ;
struct mei_cl_cb * cb , * next ;
2012-11-11 17:38:01 +02:00
bool removed = false ;
/* list all list member */
2015-02-10 10:39:45 +02:00
list_for_each_entry_safe ( cb , next , mei_cb_list , list ) {
2012-11-11 17:38:01 +02:00
/* check if list member associated with a file */
2015-02-10 10:39:45 +02:00
if ( file = = cb - > file_object ) {
2012-11-11 17:38:01 +02:00
/* check if cb equal to current iamthif cb */
2015-02-10 10:39:45 +02:00
if ( dev - > iamthif_current_cb = = cb ) {
2012-11-11 17:38:01 +02:00
dev - > iamthif_current_cb = NULL ;
/* send flow control to iamthif client */
2015-02-10 10:39:45 +02:00
mei_hbm_cl_flow_control_req ( dev , cl ) ;
2012-11-11 17:38:01 +02:00
}
/* free all allocated buffers */
2015-02-10 10:39:45 +02:00
mei_io_cb_free ( cb ) ;
2012-11-11 17:38:01 +02:00
removed = true ;
}
}
return removed ;
}
/**
* mei_clear_lists - removes all callbacks associated with file
*
* @ dev : device structure
* @ file : file structure
*
* mei_clear_lists is called to clear resources associated with file
* when application calls close function or Ctrl - C was pressed
*
2014-09-29 16:31:49 +03:00
* Return : true if callback removed from the list , false otherwise
2012-11-11 17:38:01 +02:00
*/
static bool mei_clear_lists ( struct mei_device * dev , struct file * file )
{
bool removed = false ;
/* remove callbacks associated with a file */
mei_clear_list ( dev , file , & dev - > amthif_cmd_list . list ) ;
if ( mei_clear_list ( dev , file , & dev - > amthif_rd_complete_list . list ) )
removed = true ;
2012-11-01 21:17:15 +02:00
2012-11-11 17:38:01 +02:00
mei_clear_list ( dev , file , & dev - > ctrl_rd_list . list ) ;
if ( mei_clear_list ( dev , file , & dev - > ctrl_wr_list . list ) )
removed = true ;
if ( mei_clear_list ( dev , file , & dev - > write_waiting_list . list ) )
removed = true ;
if ( mei_clear_list ( dev , file , & dev - > write_list . list ) )
removed = true ;
/* check if iamthif_current_cb not NULL */
if ( dev - > iamthif_current_cb & & ! removed ) {
/* check file and iamthif current cb association */
if ( dev - > iamthif_current_cb - > file_object = = file ) {
/* remove cb */
mei_io_cb_free ( dev - > iamthif_current_cb ) ;
dev - > iamthif_current_cb = NULL ;
removed = true ;
}
}
return removed ;
}
/**
* mei_amthif_release - the release function
*
2013-04-05 01:05:05 +09:00
* @ dev : device structure
2012-11-11 17:38:01 +02:00
* @ file : pointer to file structure
*
2014-09-29 16:31:49 +03:00
* Return : 0 on success , < 0 on error
2012-11-11 17:38:01 +02:00
*/
int mei_amthif_release ( struct mei_device * dev , struct file * file )
{
2013-09-16 23:44:47 +03:00
if ( dev - > iamthif_open_count > 0 )
dev - > iamthif_open_count - - ;
2012-11-11 17:38:01 +02:00
if ( dev - > iamthif_file_object = = file & &
dev - > iamthif_state ! = MEI_IAMTHIF_IDLE ) {
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " amthif canceled iamthif state %d \n " ,
2012-11-11 17:38:01 +02:00
dev - > iamthif_state ) ;
dev - > iamthif_canceled = true ;
if ( dev - > iamthif_state = = MEI_IAMTHIF_READ_COMPLETE ) {
2014-09-29 16:31:42 +03:00
dev_dbg ( dev - > dev , " run next amthif iamthif cb \n " ) ;
2012-11-11 17:38:01 +02:00
mei_amthif_run_next_cmd ( dev ) ;
}
}
if ( mei_clear_lists ( dev , file ) )
dev - > iamthif_state = MEI_IAMTHIF_IDLE ;
return 0 ;
}