1 /******************************************************************************
3 * Copyright (c) 2019 Intel.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 *******************************************************************************/
19 #include <linux/kernel.h>
20 #include <linux/sched.h>
21 #include <linux/module.h>
22 #include <linux/init.h>
23 #include <linux/slab.h>
24 #include <linux/interrupt.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/kthread.h>
28 #include <linux/wait.h>
29 #include <asm/uaccess.h>
33 #include "wls_debug.h"
35 #if defined(_MLOG_TRACE_)
39 #define WLS_VERSION_X 0
40 #define WLS_VERSION_Y 0
41 #define WLS_VERSION_Z 3
42 #define WLS_VERSION_RESERVED 0
43 #define WLS_DRV_VERSION ((WLS_VERSION_X << 24) | (WLS_VERSION_Y << 16) | (WLS_VERSION_Z << 8) | WLS_VERSION_RESERVED)
45 #define WLS_DRV_VERSION_FORMAT "%d.%d.%d"
46 #define WLS_DEV_DEVICE_FORMAT "wls%d"
49 #define WLS_SEMA_COUNT 32
50 #define WLS_MAX_CLIENTS 8
53 typedef struct wls_us_priv_s
63 char wls_driver_name[] = "wls";
64 char wls_driver_version[10];
65 char wls_dev_device_name[10];
67 static long wls_ioctl(struct file * filp, unsigned int cmd, unsigned long arg);
68 static int wls_open(struct inode * inode, struct file * filp);
69 static int wls_release(struct inode * inode, struct file * filp);
70 static int wls_mmap(struct file * filp, struct vm_area_struct * vma);
71 static int wls_wait(wls_sema_priv_t *priv, unsigned long arg);
72 static int wls_wake_up_user_thread(char *buf, wls_sema_priv_t *semap);
74 static struct file_operations wls_fops = {
77 .release = wls_release,
78 .unlocked_ioctl = wls_ioctl,
79 .compat_ioctl = wls_ioctl,
83 static struct wls_dev_t* wls_dev[WLS_MAX_CLIENTS];
84 static wls_drv_ctx_t wls_drv_ctx[WLS_MAX_CLIENTS];
86 static struct class * wls_class;
88 /**********************************************************************
90 **********************************************************************/
91 int wlsMaxClients = 1;
94 /**********************************************************************/
95 module_param(wlsMaxClients, int, S_IRUSR);
97 /**********************************************************************/
99 static wls_drv_ctx_t * wls_get_ctx(unsigned int id)
101 if(id < WLS_MAX_CLIENTS)
102 return &wls_drv_ctx[id];
107 int wls_wake_up_user_thread(char *buf, wls_sema_priv_t *semap)
109 if (likely(atomic_read(&semap->is_irq) < FIFO_LEN)) {
110 unsigned int put = semap->drv_block_put + 1;
113 //copy data from user
114 memcpy(&semap->drv_block[put], buf, sizeof(wls_wait_req_t));
116 semap->drv_block_put = put;
117 atomic_inc(&semap->is_irq);
119 printk(KERN_INFO "[wls]:PUT: put=%d get=%d T=%lu is_irq=%d\n",
120 semap->drv_block_put, semap->drv_block_get,
121 semap->drv_block[put].start_time , atomic_read(&semap->is_irq));
123 wake_up_interruptible(&semap->queue);
129 void wls_show_data(void* ptr, unsigned int size)
131 unsigned char *d = ptr;
134 for(i = 0; i < size; i++)
138 printk("%02x ", d[i]);
143 static int wls_open(struct inode * inode, struct file * filp)
145 if((MINOR(inode->i_rdev ) >= 0) && (MINOR(inode->i_rdev) < wlsMaxClients) && (MINOR(inode->i_rdev ) < WLS_MAX_CLIENTS)){
146 filp->private_data = (void *)wls_dev[MINOR(inode->i_rdev)];
147 WLS_DEBUG("wls_open [%d] priv: 0x%p",MINOR(inode->i_rdev), filp->private_data);
148 WLS_DEBUG("wls_open PID [%d] ", current->pid);
150 WLS_ERROR("wls_open PID [%d] incorrect inode->i_rdev %d", current->pid, MINOR(inode->i_rdev));
156 static int wls_release(struct inode * inode, struct file * filp)
158 struct wls_dev_t* wls_loc = NULL;
159 wls_us_ctx_t* pUsCtx = NULL;
160 wls_us_priv_t* pUs_priv = NULL;
161 wls_drv_ctx_t* pDrv_ctx = NULL;
164 WLS_DEBUG("priv: 0x%p", filp->private_data);
165 WLS_DEBUG("wls_release PID [%d] ",current->pid);
167 if((MINOR(inode->i_rdev ) >= 0) && (MINOR(inode->i_rdev) < wlsMaxClients) && (MINOR(inode->i_rdev ) < WLS_MAX_CLIENTS)){
168 if (filp->private_data != NULL) {
169 wls_loc = (struct wls_dev_t*)filp->private_data;
170 if((void *)wls_dev[MINOR(inode->i_rdev)] == (void *)wls_loc){
171 pDrv_ctx = (wls_drv_ctx_t*)wls_loc->pWlsDrvCtx;
173 for(i = 0; i < 2; i++ ){
174 pUsCtx = (wls_us_ctx_t*)pDrv_ctx->p_wls_us_ctx[i];
176 wls_us_ctx_t* dst = (wls_us_ctx_t*)pUsCtx->dst_kernel_va;
177 wls_wait_req_t drv_block;
179 wls_us_priv_t* pDstPriv = (wls_us_priv_t*)dst->wls_us_private;
181 drv_block.start_time = wls_rdtsc();
182 pDstPriv->NeedToWakeUp = 1;
183 wls_wake_up_user_thread((char *)&drv_block, &pDstPriv->sema);
187 pDrv_ctx->p_wls_us_ctx[i]->dst_kernel_va = (uint64_t)0;
188 pDrv_ctx->p_wls_us_ctx[i]->dst_user_va = (uint64_t)0;
189 pDrv_ctx->p_wls_us_ctx[i]->dst_pa = (uint64_t)0;
193 for(i = 0; i < 2; i++ ){
194 pUsCtx = (wls_us_ctx_t*)pDrv_ctx->p_wls_us_ctx[i];
197 pUs_priv = (wls_us_priv_t*)pUsCtx->wls_us_private;
199 if(pUs_priv->pid == current->pid){
200 if (pUs_priv->isWait == 0){
201 pUsCtx->wls_us_private = NULL;
203 pDrv_ctx->p_wls_us_ctx[i] = NULL;
204 dma_free_coherent(wls_loc->device, sizeof(wls_us_ctx_t),(void*)pUsCtx, (long)pDrv_ctx->p_wls_us_pa_ctx[i]);
205 pDrv_ctx->p_wls_us_pa_ctx[i] = NULL;
206 pDrv_ctx->nWlsClients--;
208 WLS_PRINT("Wait is in process\n");
216 filp->private_data = NULL;
219 WLS_ERROR("wls_release PID [%d] incorrect inode->i_rdev %d", current->pid, MINOR(inode->i_rdev));
225 static int wls_wait(wls_sema_priv_t *priv, unsigned long arg)
227 char __user *buf = (char __user *)arg;
229 if (!likely(atomic_read(&priv->is_irq))) {
230 if (unlikely(wait_event_interruptible(priv->queue, atomic_read(&priv->is_irq)))) {
235 atomic_dec(&priv->is_irq);
237 if (priv->drv_block_put != priv->drv_block_get) {
238 unsigned int get = priv->drv_block_get + 1;
243 if (copy_to_user(buf, &priv->drv_block[get], sizeof(wls_wait_req_t))) {
247 priv->drv_block_get = get;
250 printk(KERN_INFO "[wls]:GET: put=%d get=%d T=%lu is_irq=%d\n",
251 priv->drv_block_put, priv->drv_block_get,
252 priv->drv_block[get].start_time, atomic_read(&priv->is_irq));
257 printk(KERN_ERR "[wls]: wrong computation of queueing\n");
264 static unsigned wls_is_us_opened(wls_open_req_t *param)
271 wls_us_ctx_t *wls_create_us_ctx(wls_open_req_t *param, struct wls_dev_t * wls_loc)
273 wls_us_ctx_t* pUsCtx = NULL;
274 wls_drv_ctx_t* pDrv_ctx = wls_loc->pWlsDrvCtx;
276 // check if instance already registered
277 if(wls_is_us_opened(param))
280 // allocate memory for shared portion
281 pUsCtx = (wls_us_ctx_t*)dma_alloc_coherent(NULL, param->size, (dma_addr_t *)¶m->ctx_pa, GFP_KERNEL);
282 WLS_DEBUG("wls_create_us_ctx: pUsCtx 0x%016lx\n", (unsigned long)pUsCtx);
284 // allocate memory for private
285 wls_us_priv_t *pUs_priv = kmalloc(sizeof(wls_us_priv_t), GFP_KERNEL);
290 memset (pUsCtx, 0, sizeof(wls_us_ctx_t));
292 SFL_DefQueue(&pUsCtx->ul_free_block_pq, pUsCtx->ul_free_block_storage, UL_FREE_BLOCK_QUEUE_SIZE * sizeof(void*));
293 WLS_PRINT("ul free: off %lx\n",((U64) &pUsCtx->ul_free_block_pq -(U64)pUsCtx));
295 WLS_MsgDefineQueue(&pUsCtx->get_queue, pUsCtx->get_storage, WLS_GET_QUEUE_N_ELEMENTS, 0);
296 WLS_PRINT("get_queue: off %lx\n",((U64) &pUsCtx->get_queue -(U64)pUsCtx));
298 WLS_MsgDefineQueue(&pUsCtx->put_queue, pUsCtx->put_storage, WLS_PUT_QUEUE_N_ELEMENTS, 0);
299 WLS_PRINT("put_queue: off %lx\n",((U64) &pUsCtx->put_queue -(U64)pUsCtx));
302 memset (pUs_priv, 0, sizeof(wls_us_priv_t));
303 init_waitqueue_head(&pUs_priv->sema.queue);
304 atomic_set(&pUs_priv->sema.is_irq, 0);
306 pUs_priv->pid = current->pid;
308 pUsCtx->wls_us_private = pUs_priv;
309 WLS_DEBUG("wls_create_us_ctx: pUsCtx->wls_us_private 0x%016lx\n", (unsigned long)pUsCtx->wls_us_private);
313 pDrv_ctx->p_wls_us_ctx[pDrv_ctx->nWlsClients] = pUsCtx;
314 pDrv_ctx->p_wls_us_pa_ctx[pDrv_ctx->nWlsClients++] = (wls_us_ctx_t*)param->ctx_pa;
316 if(pDrv_ctx->p_wls_us_ctx[0] && pDrv_ctx->p_wls_us_ctx[1])
319 pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[1];
320 pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[1];
322 pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[0];
323 pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[0];
325 pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[1];
326 pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[1];
327 pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[0];
328 pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[0];
330 WLS_DEBUG("link: 0 <-> 1: 0: 0x%016lx 1: 0x%016lx\n", (long unsigned int)pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va,
331 (long unsigned int)pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va);
337 kfree(pUsCtx->wls_us_private);
339 dma_free_coherent(wls_loc->device, param->size, pUsCtx, param->ctx_pa);
345 int wls_destroy_us_ctx(wls_close_req_t *param, struct wls_dev_t * wls_prv)
347 wls_us_ctx_t* pUsCtx = NULL;
348 wls_us_priv_t* pUs_priv = NULL;
350 wls_drv_ctx_t* pDrv_ctx = wls_prv->pWlsDrvCtx;
352 if(pDrv_ctx->p_wls_us_ctx[0] && pDrv_ctx->p_wls_us_ctx[1])
355 pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)0;
356 pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)0;
357 pDrv_ctx->p_wls_us_ctx[0]->dst_user_va = (uint64_t)0;
358 pDrv_ctx->p_wls_us_ctx[1]->dst_user_va = (uint64_t)0;
359 pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t)0;
360 pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t)0;
362 WLS_DEBUG("un-link: 0 <-> 1: 0: 0x%016lx 1: 0x%016lx\n", (long unsigned int)pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va,
363 (long unsigned int)pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va);
366 pUsCtx = (wls_us_ctx_t*)param->ctx;
369 pUs_priv = (wls_us_priv_t*)pUsCtx->wls_us_private;
371 if (pUs_priv->isWait == 0){
373 pUsCtx->wls_us_private = NULL;
376 if( pDrv_ctx->p_wls_us_ctx[0] == pUsCtx){
377 pDrv_ctx->p_wls_us_ctx[0] = NULL;
378 pDrv_ctx->p_wls_us_pa_ctx[0] = NULL;
380 pDrv_ctx->p_wls_us_ctx[1] = NULL;
381 pDrv_ctx->p_wls_us_pa_ctx[1] = NULL;
383 pDrv_ctx->nWlsClients--;
384 dma_free_coherent(wls_prv->device, param->size, pUsCtx, param->ctx_pa);
386 WLS_ERROR("param->ctx_pa is NULL\n");
389 WLS_PRINT("Wait is in process\n");
396 static int wls_process_wait(wls_us_ctx_t* pUsCtx)
398 int n = WLS_GetNumItemsInTheQueue(&pUsCtx->get_queue);
403 static int wls_process_put(wls_us_ctx_t *src, wls_us_ctx_t *dst)
409 wls_us_priv_t* pDstPriv = NULL;
410 wls_wait_req_t drv_block;
412 WLS_DEBUG("offset get_queue %lx\n",(U64)&src->get_queue - (U64)src);
414 n = WLS_GetNumItemsInTheQueue(&src->put_queue);
418 if (WLS_MsgDequeue(&src->put_queue, &hMsg, NULL, (void*)src))
420 WLS_DEBUG("WLS_Get %lx %d type %d\n",(U64) hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID);
421 if(WLS_MsgEnqueue(&dst->get_queue, hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID, hMsg.flags, NULL, (void*)dst) == FALSE){ // try to send
422 if(WLS_MsgEnqueue(&src->put_queue, hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID, hMsg.flags, NULL, (void*)src) == FALSE){ // return back
423 WLS_ERROR("wls_process_put: Cannot return block to back to queue \n");
436 if(dst->wls_us_private){
437 pDstPriv = (wls_us_priv_t*)dst->wls_us_private;
439 drv_block.start_time = wls_rdtsc();
440 pDstPriv->NeedToWakeUp = 1;
441 wls_wake_up_user_thread((char *)&drv_block, &pDstPriv->sema);
449 static long wls_ioctl(struct file * filp, unsigned int cmd, unsigned long arg)
451 struct wls_dev_t * wls_prv = (struct wls_dev_t *)filp->private_data;
452 void __user * to = (void __user *)arg;
453 const void __user * from = (const void __user *)arg;
456 WLS_DEBUG("wls_ioctl PID [%d] ", current->pid);
458 if (_IOC_TYPE(cmd) != WLS_IOC_MAGIC) {
462 if (_IOC_NR(cmd) >= WLS_IOC_COUNT) {
468 wls_open_req_t param;
470 WLS_DEBUG("WLS_IOC_OPEN wls_us_ctx_t %ld\n", sizeof(wls_us_ctx_t));
471 ret = copy_from_user((void *)¶m, from, sizeof(param));
473 WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
474 (unsigned long)ret, (unsigned long)from);
478 if (sizeof(wls_drv_ctx_t) >= param.size){
479 WLS_ERROR("incorrect size %lu > %u\n", sizeof(wls_drv_ctx_t), param.size);
484 param.ctx = (uint64_t)wls_create_us_ctx(¶m, wls_prv);
485 if (param.ctx == 0) {
486 WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
487 (unsigned long)ret, (unsigned long)from);
491 WLS_DEBUG("WLS_IOC_OPEN: kva %lx pa %lx sz [%d]\n", (long unsigned int)param.ctx, (long unsigned int)param.ctx_pa, param.size);
493 ret = copy_to_user(to, (const void *)¶m, sizeof(wls_open_req_t));
495 WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
496 (unsigned long)ret, (unsigned long)from);
500 case WLS_IOC_CLOSE: {
501 wls_close_req_t param;
503 ret = copy_from_user((void *)¶m, from, sizeof(param));
505 WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
506 (unsigned long)ret, (unsigned long)from);
509 WLS_DEBUG("WLS_IOC_CLOSE: kva %lx pa %lx sz [%d]\n", (long unsigned int)param.ctx, (long unsigned int)param.ctx_pa, param.size);
511 ret = wls_destroy_us_ctx(¶m, wls_prv);
514 WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
515 (unsigned long)ret, (unsigned long)from);
521 wls_us_ctx_t* pUsCtx = NULL;
523 #if defined(_MLOG_TRACE_)
524 unsigned long t = MLOG_GETTICK();
526 ret = copy_from_user((void *)¶m, from, sizeof(param));
528 WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
529 (unsigned long)ret, (unsigned long)from);
533 pUsCtx = (wls_us_ctx_t*)param.wls_us_kernel_va;
534 if (pUsCtx == NULL) {
535 WLS_ERROR("Transaction failed %ld\n", (unsigned long)ret);
539 if(pUsCtx->dst_kernel_va)
540 ret = wls_process_put(pUsCtx, (wls_us_ctx_t*)pUsCtx->dst_kernel_va);
543 WLS_ERROR("Transaction failed %ld\n", (unsigned long)ret);
547 /* clean up for next time */
548 #if defined(_MLOG_TRACE_)
549 MLogTask(PID_WLS_DRV_IOC_PUT, t, MLOG_GETTICK());
552 case WLS_IOC_EVENT: {
553 wls_event_req_t param;
555 ret = copy_from_user((void *)¶m, from, sizeof(param));
558 WLS_ERROR("Event %ld failed %ld\n", (unsigned long)param.event_to_wls,
564 wls_wait_req_t param;
565 wls_us_ctx_t* pUsCtx = NULL;
566 wls_us_priv_t* pUsPriv = NULL;
567 #if defined(_MLOG_TRACE_)
568 unsigned long t = MLOG_GETTICK();
569 MLogTask(PID_WLS_DRV_IOC_WAIT_WAKE_ENTRY, t, 1250+t);
571 ret = copy_from_user((void *)¶m, from, sizeof(param));
573 WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
577 WLS_DEBUG("Wait pUsCtx 0x%016lx\n", (unsigned long)param.wls_us_kernel_va);
578 pUsCtx = (wls_us_ctx_t*) param.wls_us_kernel_va;
581 WLS_ERROR("Wait failed on User context %ld\n", (unsigned long)ret);
585 pUsPriv = (wls_us_priv_t*) pUsCtx->wls_us_private;
586 WLS_DEBUG("Wait pUsPriv 0x%016lx\n", (unsigned long)pUsPriv);
588 if(pUsPriv == NULL) {
590 WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
594 wls_wait(&pUsPriv->sema, (unsigned long)from);
596 memset(¶m, 0, sizeof(wls_wait_req_t));
597 param.nMsg = wls_process_wait(pUsCtx);
599 #if defined(_MLOG_TRACE_)
602 ret = copy_to_user(to, (const void *)¶m, sizeof(wls_wait_req_t));
604 WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
605 (unsigned long)ret, (unsigned long)from);
608 #if defined(_MLOG_TRACE_)
609 MLogTask(PID_WLS_DRV_IOC_WAIT_WAKE_UP, t, MLOG_GETTICK());
612 case WLS_IOC_WAKE_UP: {
613 wls_wait_req_t param;
614 wls_us_ctx_t* pUsCtx = NULL;
615 wls_us_priv_t* pUsPriv = NULL;
616 wls_wait_req_t drv_block;
618 ret = copy_from_user((void *)¶m, from, sizeof(param));
620 WLS_ERROR("WLS_IOC_WAKE_UP failed %ld\n",
625 WLS_DEBUG("Wait pUsCtx 0x%016lx\n", (unsigned long)param.wls_us_kernel_va);
626 pUsCtx = (wls_us_ctx_t*) param.wls_us_kernel_va;
629 WLS_ERROR("Wait failed on User context %ld\n", (unsigned long)ret);
633 pUsPriv = (wls_us_priv_t*) pUsCtx->wls_us_private;
634 WLS_DEBUG("Wait pUsPriv 0x%016lx\n", (unsigned long)pUsPriv);
636 if(pUsPriv == NULL) {
638 WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
642 drv_block.start_time = wls_rdtsc();
643 wls_wake_up_user_thread((char *)&drv_block, &pUsPriv->sema);
645 case WLS_IOC_CONNECT: {
646 wls_connect_req_t param;
647 wls_us_priv_t* pUsPriv = NULL;
648 wls_wait_req_t drv_block;
650 ret = copy_from_user((void *)¶m, from, sizeof(param));
652 WLS_ERROR("WLS_IOC_WAKE_UP failed %ld\n",
657 pUsPriv = (wls_us_priv_t*)param.wls_us_kernel_va;
658 drv_block.start_time = wls_rdtsc();
659 wls_wake_up_user_thread((char *)&drv_block, &pUsPriv->sema);
662 WLS_ERROR("unknown ioctl cmd: '0x%08x'", cmd);
668 WLS_ERROR("cmd_%x failed: %ld", cmd, ret);
674 static int wls_mmap(struct file * filp, struct vm_area_struct * vma)
676 struct wls_dev_t * wls = (struct wls_dev_t *)filp->private_data;
678 WLS_DEBUG("priv: 0x%p", filp->private_data);
679 WLS_DEBUG("WLS_mmap : mmap function called \n");
680 WLS_DEBUG("vma->start =%lx\n",vma->vm_start);
681 WLS_DEBUG("vma->end =%lx\n",vma->vm_end);
684 // vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
686 WLS_DEBUG("vma->pgoff =%lx\n",vma->vm_pgoff);
689 WLS_ERROR("WLS is NULL");
693 return remap_pfn_range(vma,vma->vm_start,vma->vm_pgoff,vma->vm_end-vma->vm_start,\
697 static int __init wls_init(void)
699 struct wls_dev_t* wls_dev_loc = NULL;
705 memset(&wls_dev[0], 0, sizeof(struct wls_dev_t*) * WLS_MAX_CLIENTS);
707 snprintf(wls_driver_version, 10, WLS_DRV_VERSION_FORMAT, WLS_VERSION_X, WLS_VERSION_Y, WLS_VERSION_Z);
709 WLS_PRINT("Intel(R) Wireless Subsystem Communication interface - %s\n", wls_driver_version);
710 WLS_PRINT("Copyright(c) 2014 Intel Corporation.\n");
711 //WLS_PRINT("Build: Date: %s Time: %s\n", __DATE__, __TIME__);
713 if ((wlsMaxClients > WLS_MAX_CLIENTS) || (wlsMaxClients < 1))
715 WLS_ERROR("Invalid wlsMaxClients %d\n", wlsMaxClients);
718 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
719 wls_dev_loc = (struct wls_dev_t *)kzalloc(sizeof(struct wls_dev_t), GFP_KERNEL);
720 WLS_DEBUG("wls_dev_loc %d %p", dev_cnt, wls_dev_loc);
722 if (wls_dev_loc == NULL) {
723 WLS_ERROR("no free memory (wanted %ld bytes)", sizeof(struct wls_dev_t));
727 wls_dev[dev_cnt] = wls_dev_loc;
728 WLS_DEBUG("wls_init [%d]: 0x%p",dev_cnt, wls_dev[dev_cnt]);
731 res = alloc_chrdev_region(&dev_no, minor_no, wlsMaxClients, MODNAME);
733 WLS_ERROR("failed alloc char dev region: %d", res);
737 wls_class = class_create(THIS_MODULE, wls_driver_name);
739 wls_dev_loc = wls_dev[0];
740 wls_dev_loc->dev_no = dev_no;
742 cdev_init(&wls_dev_loc->cdev, &wls_fops);
743 wls_dev_loc->cdev.owner = THIS_MODULE;
744 wls_dev_loc->cdev.ops = &wls_fops;
745 res = cdev_add(&wls_dev_loc->cdev, dev_no, wlsMaxClients);
748 WLS_ERROR("failed add char dev: %d", res);
753 if (IS_ERR((void *)wls_class)) {
754 WLS_ERROR("failed create class");
759 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
760 wls_dev_loc = wls_dev[dev_cnt];
761 if (wls_dev_loc == NULL ) {
762 WLS_ERROR("wls_dev_loc is NULL");
766 if(wlsMaxClients > 1){
767 snprintf(wls_dev_device_name, 10, WLS_DEV_DEVICE_FORMAT, dev_cnt);
769 snprintf(wls_dev_device_name, 10, "%s", MODNAME);
772 wls_dev_loc->dev_no = MKDEV(MAJOR(dev_no), dev_cnt);
773 wls_dev_loc->device = device_create(wls_class, NULL, wls_dev_loc->dev_no, NULL, wls_dev_device_name);
775 if (IS_ERR((void *)wls_dev_loc->device)) {
776 WLS_ERROR("failed create / device");
781 dev_info(wls_dev_loc->device, "Device: %s\n", wls_dev_device_name);
782 mutex_init(&wls_dev_loc->lock);
784 wls_dev_loc->pWlsDrvCtx = wls_get_ctx(dev_cnt);
786 if (wls_dev_loc->pWlsDrvCtx == NULL) {
787 WLS_ERROR("failed wls_get_ctx(%d)", dev_cnt);
796 WLS_PRINT("init %d /dev/wlsX communication devices [0-%d]\n", dev_cnt, dev_cnt-1);
800 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
801 wls_dev_loc = wls_dev[dev_cnt];
803 device_destroy(wls_class, wls_dev_loc->dev_no);
804 cdev_del(&wls_dev_loc->cdev);
807 class_destroy(wls_class);
809 unregister_chrdev_region(wls_dev[0]->dev_no, wlsMaxClients);
811 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
812 if(wls_dev[dev_cnt]){
813 kfree(wls_dev[dev_cnt]);
814 wls_dev[dev_cnt] = NULL;
818 WLS_ERROR("init failed");
822 static void __exit wls_exit(void)
824 struct wls_dev_t* wls_dev_loc = NULL;
828 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
829 wls_dev_loc = wls_dev[dev_cnt];
830 device_destroy(wls_class, wls_dev_loc->dev_no);
832 wls_dev_loc = wls_dev[0];
834 cdev_del(&wls_dev_loc->cdev);
835 class_destroy(wls_class);
837 unregister_chrdev_region(wls_dev[0]->dev_no, wlsMaxClients);
839 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
840 if(wls_dev[dev_cnt]){
841 kfree(wls_dev[dev_cnt]);
842 wls_dev[dev_cnt] = NULL;
847 WLS_PRINT("Intel(R) Wireless Subsystem Communication interface - %s was removed\n", wls_driver_version);
850 MODULE_DESCRIPTION("Wirelsess Sybsytem Communication interface");
851 MODULE_AUTHOR("Intel Corporation");
852 MODULE_LICENSE("GPL v2");
853 MODULE_VERSION("WLS_DRV_VERSION_FORMAT");
855 module_init(wls_init);
856 module_exit(wls_exit);