1 /**************************************************************************** 2 **+-----------------------------------------------------------------------+** 3 **| |** 4 **| Copyright(c) 1998 - 2008 Texas Instruments. All rights reserved. |** 5 **| All rights reserved. |** 6 **| |** 7 **| Redistribution and use in source and binary forms, with or without |** 8 **| modification, are permitted provided that the following conditions |** 9 **| are met: |** 10 **| |** 11 **| * Redistributions of source code must retain the above copyright |** 12 **| notice, this list of conditions and the following disclaimer. |** 13 **| * Redistributions in binary form must reproduce the above copyright |** 14 **| notice, this list of conditions and the following disclaimer in |** 15 **| the documentation and/or other materials provided with the |** 16 **| distribution. |** 17 **| * Neither the name Texas Instruments nor the names of its |** 18 **| contributors may be used to endorse or promote products derived |** 19 **| from this software without specific prior written permission. |** 20 **| |** 21 **| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |** 22 **| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |** 23 **| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |** 24 **| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |** 25 **| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |** 26 **| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |** 27 **| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |** 28 **| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |** 29 **| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |** 30 **| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |** 31 **| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |** 32 **| |** 33 **+-----------------------------------------------------------------------+** 34 ****************************************************************************/ 35 36 37 #include "arch_ti.h" 38 39 #include <asm/uaccess.h> /* copy_to_user() */ 40 #include <linux/netdevice.h> 41 #include <linux/ioctl.h> 42 #include <linux/completion.h> 43 #include <linux/vmalloc.h> 44 45 #include "esta_drv.h" 46 #include "tiwlan_profile.h" 47 #include "ioctl_init.h" 48 #include "ioctl_utils.h" 49 #include "tiioctl.h" 50 #include "ipc_k.h" 51 52 53 void print_priv_ioctl_params(struct net_device *dev, tiioctl_req_t *req, char *extra) 54 { 55 print_deb(" priv_ioctl_params(*dev:%p,*req:%p, *extra:%p)\n", dev, req, extra); 56 print_deb(" wrqu.point: user_data=%p, length=%ld, cmd=%ld\n", (void *) req->user_data_pointer, 57 req->length, req->cmd ); 58 print_deb(" wrqu dump: "); 59 print_memory_dump((char *) req, sizeof(*req) ); 60 print_deb("\n"); 61 62 if( extra ) 63 { 64 print_deb(" extra (%p) :", extra ); 65 print_memory_dump(extra, req->length ); 66 print_deb("\n"); 67 } 68 } 69 70 /*sends complete to the user after to signal the completion of the asynchronous */ 71 /*operation (need to set *pIoCompleteFlag = FALSE, at osCmd.c).*/ 72 73 void os_IoctlComplete(PTIWLN_ADAPTER_T pAdapter, TI_STATUS ReturnStatus ) 74 { 75 *pAdapter->pCompleteReply = (int)ReturnStatus; 76 complete(pAdapter->IoctlComp); 77 } 78 79 80 NTSTATUS DispatchCommand(PTIWLN_ADAPTER_T pAdapter,ULONG ioControlCode,PULONG outBufLen, 81 ULONG inBufLen,PVOID ioBuffer,PUINT8 pIoCompleteFlag); 82 83 int ti1610_ioctl_priv_proc_tl(tiwlan_req_t *req_data) 84 { 85 struct net_device *dev = req_data->drv->netdev; 86 tiioctl_req_t *req = (tiioctl_req_t *) req_data->u.req.p1; 87 static unsigned int drv_started = 0; 88 static UINT8 IoCompleteFlag ; 89 90 ULONG *data = (ULONG *) req_data->u.req.p2; 91 92 int res = -EINVAL; 93 94 print_deb("priv_ioctl_proc(): cmd=%ld, data=%p (user_data=%lx), lenght=%ld\n", 95 req->cmd, data, req->user_data_pointer, req->length); 96 if( !drv_started && (req->cmd != TIWLN_DRIVER_STATUS_SET)) { /* Dm: Fix */ 97 return res; 98 } 99 100 switch( req->cmd ) { 101 case TIWLN_DRIVER_STATUS_SET: 102 if(*data) 103 res = tiwlan_start_drv( (tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev) ); 104 else 105 res = tiwlan_stop_drv( (tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev) ); 106 107 if( res == OK ) 108 drv_started = !drv_started; 109 break; 110 111 case TIWLN_SEND_EAPOL_PACKET: 112 res = os_sendPacket(dev, data, req->length); 113 break; 114 #ifdef TI_DBG 115 case TIWLN_DRIVER_DEBUG_PRINT: 116 res = util_hal_debug_print(dev, data); 117 break; 118 #endif /* TI_DBG */ 119 default: 120 { 121 res = DispatchCommand(&req_data->drv->adapter, req->cmd, &req->length, req->length, data,&IoCompleteFlag ); 122 /* If we do not have to send complete to user back then set the Falg to FALSE 123 The Complete will be sent from another contect of command completion from FW */ 124 if(IoCompleteFlag == FALSE) 125 { 126 req_data->u.req.reply_expected = FALSE; 127 /****** TO DO - This solution will have a problem in case of two async ioctrls (in case of two utility adapters). ******/ 128 /* Store the semaphore for later competion */ 129 (req_data->drv->adapter).IoctlComp = &(req_data->u.req.comp); 130 /* Store the pointer of the result status for later competion */ 131 (req_data->drv->adapter).pCompleteReply = &(req_data->u.reply); 132 } 133 134 } 135 } 136 return res; 137 } 138 139 int ti1610_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 140 { 141 tiioctl_req_t *req = (tiioctl_req_t *) &rq->ifr_ifru; 142 char *extra, *kbuf = NULL; 143 int res, aval_data_size = ((char *) req + sizeof(*req)) - (char *)&req->user_data_pointer; /* = ~4 bytes */ 144 /*int is_get_cmd = (req->cmd_type & IOCTL_GET);*/ 145 146 print_deb("ti1610_do_ioctl(cmd=%lu(%s%s)) - user_data_pointer=0x%lx, len = %lu, aval_data_size=%d\n", 147 req->cmd, 148 (req->cmd_type & IOCTL_GET) ? "GET" : "", (req->cmd_type & IOCTL_SET) ? "SET" : "", 149 req->user_data_pointer, req->length, aval_data_size ); 150 151 /* driver is already initialized */ 152 if ((req->cmd == TIWLN_SET_INIT_INFO) && (((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev))->adapter.CoreHalCtx)) 153 { 154 return 0; 155 } 156 157 if( req->length > aval_data_size ) 158 { 159 if( req->user_data_pointer == 0 ) 160 return -EFAULT; 161 162 print_deb("ti1610_do_ioctl() - alloc %ld bytes\n", req->length ); 163 kbuf = extra = os_memoryAlloc(NULL,req->length); 164 #ifdef TI_MEM_ALLOC_TRACE 165 os_printf("MTT:%s:%d ::kmalloc(%lu, %x) : %lu\n", __FUNCTION__, __LINE__, req->length, GFP_KERNEL, req->length); 166 #endif/*I_MEM_ALLOC_TRACE*/ 167 168 if( !extra ) 169 return -ENOBUFS; 170 if( req->cmd_type & IOCTL_SET ) 171 { 172 if( copy_from_user(extra, (void *) req->user_data_pointer, req->length) ) 173 return -EFAULT; 174 } 175 else { 176 os_memoryZero( NULL, extra, req->length ); 177 } 178 } else 179 extra = (char *) &req->user_data_pointer; 180 181 /* Driver initialization must be performed in process context. 182 The rest is handled in the context of dedicated tasklet 183 */ 184 if (req->cmd == TIWLN_SET_INIT_INFO) 185 { 186 tiwlan_dev_init_t *init_info = (tiwlan_dev_init_t *)extra; 187 print_deb("TIWLN_SET_INIT_INFO: el=%d il=%d, fl=%d\n", 188 init_info?init_info->eeprom_image_length:0, 189 init_info?init_info->init_file_length:0, 190 init_info?init_info->firmware_image_length:0 ); 191 res = tiwlan_init_drv((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev), init_info); 192 } 193 194 #ifdef DRIVER_PROFILING 195 else if (req->cmd == TIWLAN_PROFILING_REPORT) 196 { 197 res = tiwlan_profile_report((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev)); 198 } 199 else if (req->cmd == TIWLAN_PROFILING_CPU_ESTIMATOR_CMD) { 200 /* get the command cpu estimator command parameter */ 201 unsigned int command_param = *((unsigned int *)extra); 202 /* extract the command type which is the MSB byte of the command param*/ 203 unsigned int command_type = 0xFF & (command_param >> 24); 204 /* extract the data of the command which are the 3 LSB bytes of the command param */ 205 unsigned int command_data = 0xFFFFFF & command_param; 206 /* execute the command according to its type */ 207 switch (command_type) 208 { 209 case TIWLAN_PROFILING_CPU_ESTIMATOR_CMD_START: 210 res = tiwlan_profile_cpu_usage_estimator_start((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev), 211 /* the data in this case is the estimator 212 resolution in milliseconds */ 213 command_data * 1000); 214 break; 215 case TIWLAN_PROFILING_CPU_ESTIMATOR_CMD_STOP: 216 res = tiwlan_profile_cpu_usage_estimator_stop((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev)); 217 break; 218 case TIWLAN_PROFILING_CPU_ESTIMATOR_CMD_RESET: 219 res =tiwlan_profile_cpu_usage_estimator_reset((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev)); 220 break; 221 default: 222 res = 0; 223 printk("\n\n%s: cpu usage estimator unknow command: param = %x\n\n\n", 224 __FUNCTION__, command_param); 225 } 226 } 227 #endif 228 229 else 230 { 231 res = tiwlan_send_wait_reply((tiwlan_net_dev_t *)NETDEV_GET_PRIVATE(dev), ti1610_ioctl_priv_proc_tl, 232 (unsigned long)req, (unsigned long)extra, 0, 0); 233 } 234 235 if( !res ) 236 { 237 if( (req->cmd_type & IOCTL_GET) && kbuf /*req->length > aval_data_size*/ ) 238 { 239 print_deb("ti1610_do_ioctl(): ...copy from %p to %p %ld bytes\n\n", extra, (void *) req->user_data_pointer, req->length ); 240 print_memory_dump(extra, min(32,(int) req->length) ); 241 if( copy_to_user( (void *) req->user_data_pointer, extra, req->length ) ) 242 return -EFAULT; 243 } 244 } 245 print_deb("ti1610_do_ioctl() = %d (req = %p, user_data_pointer=0x%lx, extra=%p)\n\n", res, req, req->user_data_pointer, extra ); 246 247 if( kbuf ){ 248 os_memoryFree(NULL,kbuf,sizeof(kbuf)); 249 #ifdef TI_MEM_ALLOC_TRACE 250 os_printf("MTT:%s:%d ::kfree(0x%p) : %d\n", __FUNCTION__, __LINE__, kbuf, -req->length); 251 #endif/*I_MEM_ALLOC_TRACE*/ 252 } 253 return res; 254 } 255 256 257 int tiwlan_ioctl_init( struct net_device *dev ) 258 { 259 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) 260 dev->do_ioctl = ti1610_do_ioctl; 261 #endif 262 return 0; 263 } 264