blob: 3d5b7d4a2e7ec1f41a017bf9c7395fa4201c7359 [file] [log] [blame]
/****************************************************************************
**+-----------------------------------------------------------------------+**
**| |**
**| Copyright(c) 1998 - 2008 Texas Instruments. All rights reserved. |**
**| All rights reserved. |**
**| |**
**| Redistribution and use in source and binary forms, with or without |**
**| modification, are permitted provided that the following conditions |**
**| are met: |**
**| |**
**| * Redistributions of source code must retain the above copyright |**
**| notice, this list of conditions and the following disclaimer. |**
**| * Redistributions in binary form must reproduce the above copyright |**
**| notice, this list of conditions and the following disclaimer in |**
**| the documentation and/or other materials provided with the |**
**| distribution. |**
**| * Neither the name Texas Instruments nor the names of its |**
**| contributors may be used to endorse or promote products derived |**
**| from this software without specific prior written permission. |**
**| |**
**| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |**
**| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |**
**| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |**
**| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |**
**| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |**
**| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |**
**| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |**
**| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |**
**| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |**
**| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |**
**| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |**
**| |**
**+-----------------------------------------------------------------------+**
****************************************************************************/
#include "arch_ti.h"
#include <asm/uaccess.h> /* copy_to_user() */
#include <linux/netdevice.h>
#include <linux/ioctl.h>
#include <linux/completion.h>
#include <linux/vmalloc.h>
#include "esta_drv.h"
#include "tiwlan_profile.h"
#include "ioctl_init.h"
#include "ioctl_utils.h"
#include "tiioctl.h"
#include "ipc_k.h"
void print_priv_ioctl_params(struct net_device *dev, tiioctl_req_t *req, char *extra)
{
print_deb(" priv_ioctl_params(*dev:%p,*req:%p, *extra:%p)\n", dev, req, extra);
print_deb(" wrqu.point: user_data=%p, length=%ld, cmd=%ld\n", (void *) req->user_data_pointer,
req->length, req->cmd );
print_deb(" wrqu dump: ");
print_memory_dump((char *) req, sizeof(*req) );
print_deb("\n");
if( extra )
{
print_deb(" extra (%p) :", extra );
print_memory_dump(extra, req->length );
print_deb("\n");
}
}
/*sends complete to the user after to signal the completion of the asynchronous */
/*operation (need to set *pIoCompleteFlag = FALSE, at osCmd.c).*/
void os_IoctlComplete(PTIWLN_ADAPTER_T pAdapter, TI_STATUS ReturnStatus )
{
*pAdapter->pCompleteReply = (int)ReturnStatus;
complete(pAdapter->IoctlComp);
}
NTSTATUS DispatchCommand(PTIWLN_ADAPTER_T pAdapter,ULONG ioControlCode,PULONG outBufLen,
ULONG inBufLen,PVOID ioBuffer,PUINT8 pIoCompleteFlag);
int ti1610_ioctl_priv_proc_tl(tiwlan_req_t *req_data)
{
struct net_device *dev = req_data->drv->netdev;
tiioctl_req_t *req = (tiioctl_req_t *) req_data->u.req.p1;
static unsigned int drv_started = 0;
static UINT8 IoCompleteFlag ;
ULONG *data = (ULONG *) req_data->u.req.p2;
int res = -EINVAL;
print_deb("priv_ioctl_proc(): cmd=%ld, data=%p (user_data=%lx), lenght=%ld\n",
req->cmd, data, req->user_data_pointer, req->length);
if( !drv_started && (req->cmd != TIWLN_DRIVER_STATUS_SET)) { /* Dm: Fix */
return res;
}
switch( req->cmd ) {
case TIWLN_DRIVER_STATUS_SET:
if(*data)
res = tiwlan_start_drv( (tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev) );
else
res = tiwlan_stop_drv( (tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev) );
if( res == OK )
drv_started = !drv_started;
break;
case TIWLN_SEND_EAPOL_PACKET:
res = os_sendPacket(dev, data, req->length);
break;
#ifdef TI_DBG
case TIWLN_DRIVER_DEBUG_PRINT:
res = util_hal_debug_print(dev, data);
break;
#endif /* TI_DBG */
default:
{
res = DispatchCommand(&req_data->drv->adapter, req->cmd, &req->length, req->length, data,&IoCompleteFlag );
/* If we do not have to send complete to user back then set the Falg to FALSE
The Complete will be sent from another contect of command completion from FW */
if(IoCompleteFlag == FALSE)
{
req_data->u.req.reply_expected = FALSE;
/****** TO DO - This solution will have a problem in case of two async ioctrls (in case of two utility adapters). ******/
/* Store the semaphore for later competion */
(req_data->drv->adapter).IoctlComp = &(req_data->u.req.comp);
/* Store the pointer of the result status for later competion */
(req_data->drv->adapter).pCompleteReply = &(req_data->u.reply);
}
}
}
return res;
}
int ti1610_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
tiioctl_req_t *req = (tiioctl_req_t *) &rq->ifr_ifru;
char *extra, *kbuf = NULL;
int res, aval_data_size = ((char *) req + sizeof(*req)) - (char *)&req->user_data_pointer; /* = ~4 bytes */
/*int is_get_cmd = (req->cmd_type & IOCTL_GET);*/
print_deb("ti1610_do_ioctl(cmd=%lu(%s%s)) - user_data_pointer=0x%lx, len = %lu, aval_data_size=%d\n",
req->cmd,
(req->cmd_type & IOCTL_GET) ? "GET" : "", (req->cmd_type & IOCTL_SET) ? "SET" : "",
req->user_data_pointer, req->length, aval_data_size );
/* driver is already initialized */
if ((req->cmd == TIWLN_SET_INIT_INFO) && (((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev))->adapter.CoreHalCtx))
{
return 0;
}
if( req->length > aval_data_size )
{
if( req->user_data_pointer == 0 )
return -EFAULT;
print_deb("ti1610_do_ioctl() - alloc %ld bytes\n", req->length );
kbuf = extra = os_memoryAlloc(NULL,req->length);
#ifdef TI_MEM_ALLOC_TRACE
os_printf("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", __FUNCTION__, __LINE__, req->length, GFP_KERNEL, req->length);
#endif/*I_MEM_ALLOC_TRACE*/
if( !extra )
return -ENOBUFS;
if( req->cmd_type & IOCTL_SET )
{
if( copy_from_user(extra, (void *) req->user_data_pointer, req->length) )
return -EFAULT;
}
else {
os_memoryZero( NULL, extra, req->length );
}
} else
extra = (char *) &req->user_data_pointer;
/* Driver initialization must be performed in process context.
The rest is handled in the context of dedicated tasklet
*/
if (req->cmd == TIWLN_SET_INIT_INFO)
{
tiwlan_dev_init_t *init_info = (tiwlan_dev_init_t *)extra;
print_deb("TIWLN_SET_INIT_INFO: el=%d il=%d, fl=%d\n",
init_info?init_info->eeprom_image_length:0,
init_info?init_info->init_file_length:0,
init_info?init_info->firmware_image_length:0 );
res = tiwlan_init_drv((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev), init_info);
}
#ifdef DRIVER_PROFILING
else if (req->cmd == TIWLAN_PROFILING_REPORT)
{
res = tiwlan_profile_report((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev));
}
else if (req->cmd == TIWLAN_PROFILING_CPU_ESTIMATOR_CMD) {
/* get the command cpu estimator command parameter */
unsigned int command_param = *((unsigned int *)extra);
/* extract the command type which is the MSB byte of the command param*/
unsigned int command_type = 0xFF & (command_param >> 24);
/* extract the data of the command which are the 3 LSB bytes of the command param */
unsigned int command_data = 0xFFFFFF & command_param;
/* execute the command according to its type */
switch (command_type)
{
case TIWLAN_PROFILING_CPU_ESTIMATOR_CMD_START:
res = tiwlan_profile_cpu_usage_estimator_start((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev),
/* the data in this case is the estimator
resolution in milliseconds */
command_data * 1000);
break;
case TIWLAN_PROFILING_CPU_ESTIMATOR_CMD_STOP:
res = tiwlan_profile_cpu_usage_estimator_stop((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev));
break;
case TIWLAN_PROFILING_CPU_ESTIMATOR_CMD_RESET:
res =tiwlan_profile_cpu_usage_estimator_reset((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev));
break;
default:
res = 0;
printk("\n\n%s: cpu usage estimator unknow command: param = %x\n\n\n",
__FUNCTION__, command_param);
}
}
#endif
else
{
res = tiwlan_send_wait_reply((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev), ti1610_ioctl_priv_proc_tl,
(unsigned long)req, (unsigned long)extra, 0, 0);
}
if( !res )
{
if( (req->cmd_type & IOCTL_GET) && kbuf /*req->length > aval_data_size*/ )
{
print_deb("ti1610_do_ioctl(): ...copy from %p to %p %ld bytes\n\n", extra, (void *) req->user_data_pointer, req->length );
print_memory_dump(extra, min(32,(int) req->length) );
if( copy_to_user( (void *) req->user_data_pointer, extra, req->length ) )
return -EFAULT;
}
}
print_deb("ti1610_do_ioctl() = %d (req = %p, user_data_pointer=0x%lx, extra=%p)\n\n", res, req, req->user_data_pointer, extra );
if( kbuf ){
os_memoryFree(NULL,kbuf,sizeof(kbuf));
#ifdef TI_MEM_ALLOC_TRACE
os_printf("MTT:%s:%d ::kfree(0x%p) : %d\n", __FUNCTION__, __LINE__, kbuf, -req->length);
#endif/*I_MEM_ALLOC_TRACE*/
}
return res;
}
int tiwlan_ioctl_init( struct net_device *dev )
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
dev->do_ioctl = ti1610_do_ioctl;
#endif
return 0;
}