]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/ath6kl/os/linux/ar6000_raw_if.c
Merge branch 'master' into tk71
[mv-sheeva.git] / drivers / staging / ath6kl / os / linux / ar6000_raw_if.c
diff --git a/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c b/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c
new file mode 100644 (file)
index 0000000..6b8eeea
--- /dev/null
@@ -0,0 +1,455 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2004-2010 Atheros Communications Inc.
+// All rights reserved.
+//
+// 
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+//
+//
+// Author(s): ="Atheros"
+//------------------------------------------------------------------------------
+
+#include "ar6000_drv.h"
+
+#ifdef HTC_RAW_INTERFACE
+
+static void
+ar6000_htc_raw_read_cb(void *Context, HTC_PACKET *pPacket)
+{
+    AR_SOFTC_T        *ar = (AR_SOFTC_T *)Context;
+    raw_htc_buffer    *busy;
+    HTC_RAW_STREAM_ID streamID; 
+    AR_RAW_HTC_T *arRaw = ar->arRawHtc;
+
+    busy = (raw_htc_buffer *)pPacket->pPktContext;
+    A_ASSERT(busy != NULL);
+
+    if (pPacket->Status == A_ECANCELED) {
+        /*
+         * HTC provides A_ECANCELED status when it doesn't want to be refilled
+         * (probably due to a shutdown)
+         */
+        return;
+    }
+
+    streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint);
+    A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED);
+    
+#ifdef CF
+   if (down_trylock(&arRaw->raw_htc_read_sem[streamID])) {
+#else
+    if (down_interruptible(&arRaw->raw_htc_read_sem[streamID])) {
+#endif /* CF */
+        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to down the semaphore\n"));
+    }
+
+    A_ASSERT((pPacket->Status != A_OK) || 
+             (pPacket->pBuffer == (busy->data + HTC_HEADER_LEN)));
+
+    busy->length = pPacket->ActualLength + HTC_HEADER_LEN;
+    busy->currPtr = HTC_HEADER_LEN;
+    arRaw->read_buffer_available[streamID] = TRUE;
+    //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("raw read cb:  0x%X 0x%X \n", busy->currPtr,busy->length);
+    up(&arRaw->raw_htc_read_sem[streamID]);
+
+    /* Signal the waiting process */
+    AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Waking up the StreamID(%d) read process\n", streamID));
+    wake_up_interruptible(&arRaw->raw_htc_read_queue[streamID]);
+}
+
+static void
+ar6000_htc_raw_write_cb(void *Context, HTC_PACKET *pPacket)
+{
+    AR_SOFTC_T          *ar = (AR_SOFTC_T  *)Context;
+    raw_htc_buffer      *free;
+    HTC_RAW_STREAM_ID   streamID;
+    AR_RAW_HTC_T *arRaw = ar->arRawHtc;
+    
+    free = (raw_htc_buffer *)pPacket->pPktContext;
+    A_ASSERT(free != NULL);
+
+    if (pPacket->Status == A_ECANCELED) {
+        /*
+         * HTC provides A_ECANCELED status when it doesn't want to be refilled
+         * (probably due to a shutdown)
+         */
+        return;
+    }
+
+    streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint);
+    A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED);
+    
+#ifdef CF
+    if (down_trylock(&arRaw->raw_htc_write_sem[streamID])) {
+#else
+    if (down_interruptible(&arRaw->raw_htc_write_sem[streamID])) {
+#endif
+        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to down the semaphore\n"));
+    }
+
+    A_ASSERT(pPacket->pBuffer == (free->data + HTC_HEADER_LEN));
+
+    free->length = 0;
+    arRaw->write_buffer_available[streamID] = TRUE;
+    up(&arRaw->raw_htc_write_sem[streamID]);
+
+    /* Signal the waiting process */
+    AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Waking up the StreamID(%d) write process\n", streamID));
+    wake_up_interruptible(&arRaw->raw_htc_write_queue[streamID]);
+}
+
+/* connect to a service */
+static A_STATUS ar6000_connect_raw_service(AR_SOFTC_T        *ar,
+                                           HTC_RAW_STREAM_ID StreamID)
+{
+    A_STATUS                 status;
+    HTC_SERVICE_CONNECT_RESP response;
+    A_UINT8                  streamNo;
+    HTC_SERVICE_CONNECT_REQ  connect;
+    
+    do {      
+        
+        A_MEMZERO(&connect,sizeof(connect));
+            /* pass the stream ID as meta data to the RAW streams service */
+        streamNo = (A_UINT8)StreamID;
+        connect.pMetaData = &streamNo;
+        connect.MetaDataLength = sizeof(A_UINT8);
+            /* these fields are the same for all endpoints */
+        connect.EpCallbacks.pContext = ar;
+        connect.EpCallbacks.EpTxComplete = ar6000_htc_raw_write_cb;   
+        connect.EpCallbacks.EpRecv = ar6000_htc_raw_read_cb;   
+            /* simple interface, we don't need these optional callbacks */      
+        connect.EpCallbacks.EpRecvRefill = NULL;
+        connect.EpCallbacks.EpSendFull = NULL;
+        connect.MaxSendQueueDepth = RAW_HTC_WRITE_BUFFERS_NUM;  
+        
+            /* connect to the raw streams service, we may be able to get 1 or more
+             * connections, depending on WHAT is running on the target */
+        connect.ServiceID = HTC_RAW_STREAMS_SVC;
+        
+        A_MEMZERO(&response,sizeof(response));
+        
+            /* try to connect to the raw stream, it is okay if this fails with 
+             * status HTC_SERVICE_NO_MORE_EP */
+        status = HTCConnectService(ar->arHtcTarget, 
+                                   &connect,
+                                   &response);
+        
+        if (A_FAILED(status)) {
+            if (response.ConnectRespCode == HTC_SERVICE_NO_MORE_EP) {
+                AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC RAW , No more streams allowed \n"));
+                status = A_OK;    
+            }
+            break;    
+        }
+
+            /* set endpoint mapping for the RAW HTC streams */
+        arSetRawStream2EndpointIDMap(ar,StreamID,response.Endpoint);
+
+        AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("HTC RAW : stream ID: %d, endpoint: %d\n", 
+                        StreamID, arRawStream2EndpointID(ar,StreamID)));
+        
+    } while (FALSE);
+    
+    return status;
+}
+
+int ar6000_htc_raw_open(AR_SOFTC_T *ar)
+{
+    A_STATUS status;
+    int streamID, endPt, count2;
+    raw_htc_buffer *buffer;
+    HTC_SERVICE_ID servicepriority;
+    AR_RAW_HTC_T *arRaw = ar->arRawHtc;
+    if (!arRaw) {
+        arRaw = ar->arRawHtc = A_MALLOC(sizeof(AR_RAW_HTC_T));
+        if (arRaw) {
+            A_MEMZERO(arRaw, sizeof(AR_RAW_HTC_T));
+        }
+    }
+    A_ASSERT(ar->arHtcTarget != NULL);
+    if (!arRaw) {
+        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Faile to allocate memory for HTC RAW interface\n"));
+        return -ENOMEM;
+    }
+    /* wait for target */
+    status = HTCWaitTarget(ar->arHtcTarget);
+        
+    if (A_FAILED(status)) {
+        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTCWaitTarget failed (%d)\n", status));
+        return -ENODEV;  
+    }
+    
+    for (endPt = 0; endPt < ENDPOINT_MAX; endPt++) {
+        arRaw->arEp2RawMapping[endPt] = HTC_RAW_STREAM_NOT_MAPPED;
+    }
+        
+    for (streamID = HTC_RAW_STREAM_0; streamID < HTC_RAW_STREAM_NUM_MAX; streamID++) {
+        /* Initialize the data structures */
+       sema_init(&arRaw->raw_htc_read_sem[streamID], 1);
+       sema_init(&arRaw->raw_htc_write_sem[streamID], 1);
+        init_waitqueue_head(&arRaw->raw_htc_read_queue[streamID]);
+        init_waitqueue_head(&arRaw->raw_htc_write_queue[streamID]);
+
+            /* try to connect to the raw service */
+        status = ar6000_connect_raw_service(ar,streamID);
+        
+        if (A_FAILED(status)) {
+            break;    
+        }
+        
+        if (arRawStream2EndpointID(ar,streamID) == 0) {
+            break;    
+        }
+        
+        for (count2 = 0; count2 < RAW_HTC_READ_BUFFERS_NUM; count2 ++) {
+            /* Initialize the receive buffers */
+            buffer = &arRaw->raw_htc_write_buffer[streamID][count2];
+            memset(buffer, 0, sizeof(raw_htc_buffer));
+            buffer = &arRaw->raw_htc_read_buffer[streamID][count2];
+            memset(buffer, 0, sizeof(raw_htc_buffer));
+            
+            SET_HTC_PACKET_INFO_RX_REFILL(&buffer->HTCPacket,
+                                          buffer,
+                                          buffer->data,
+                                          HTC_RAW_BUFFER_SIZE,
+                                          arRawStream2EndpointID(ar,streamID));
+            
+            /* Queue buffers to HTC for receive */
+            if ((status = HTCAddReceivePkt(ar->arHtcTarget, &buffer->HTCPacket)) != A_OK)
+            {
+                BMIInit();
+                return -EIO;
+            }
+        }
+
+        for (count2 = 0; count2 < RAW_HTC_WRITE_BUFFERS_NUM; count2 ++) {
+            /* Initialize the receive buffers */
+            buffer = &arRaw->raw_htc_write_buffer[streamID][count2];
+            memset(buffer, 0, sizeof(raw_htc_buffer));
+        }
+
+        arRaw->read_buffer_available[streamID] = FALSE;
+        arRaw->write_buffer_available[streamID] = TRUE;
+    }
+    
+    if (A_FAILED(status)) {
+        return -EIO;    
+    }
+    
+    AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("HTC RAW, number of streams the target supports: %d \n", streamID));
+            
+    servicepriority = HTC_RAW_STREAMS_SVC;  /* only 1 */
+    
+        /* set callbacks and priority list */
+    HTCSetCreditDistribution(ar->arHtcTarget,
+                             ar,
+                             NULL,  /* use default */
+                             NULL,  /* use default */
+                             &servicepriority,
+                             1);
+
+    /* Start the HTC component */
+    if ((status = HTCStart(ar->arHtcTarget)) != A_OK) {
+        BMIInit();
+        return -EIO;
+    }
+
+    (ar)->arRawIfInit = TRUE;
+    
+    return 0;
+}
+
+int ar6000_htc_raw_close(AR_SOFTC_T *ar)
+{
+    A_PRINTF("ar6000_htc_raw_close called \n");
+    HTCStop(ar->arHtcTarget);
+    
+        /* reset the device */
+    ar6000_reset_device(ar->arHifDevice, ar->arTargetType, TRUE, FALSE);
+    /* Initialize the BMI component */
+    BMIInit();
+
+    return 0;
+}
+
+raw_htc_buffer *
+get_filled_buffer(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID)
+{
+    int count;
+    raw_htc_buffer *busy;
+    AR_RAW_HTC_T *arRaw = ar->arRawHtc;
+
+    /* Check for data */
+    for (count = 0; count < RAW_HTC_READ_BUFFERS_NUM; count ++) {
+        busy = &arRaw->raw_htc_read_buffer[StreamID][count];
+        if (busy->length) {
+            break;
+        }
+    }
+    if (busy->length) {
+        arRaw->read_buffer_available[StreamID] = TRUE;
+    } else {
+        arRaw->read_buffer_available[StreamID] = FALSE;
+    }
+
+    return busy;
+}
+
+ssize_t ar6000_htc_raw_read(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID, 
+                            char __user *buffer, size_t length)
+{
+    int readPtr;
+    raw_htc_buffer *busy;
+    AR_RAW_HTC_T *arRaw = ar->arRawHtc;
+
+    if (arRawStream2EndpointID(ar,StreamID) == 0) {
+        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("StreamID(%d) not connected! \n", StreamID));
+        return -EFAULT;    
+    }
+    
+    if (down_interruptible(&arRaw->raw_htc_read_sem[StreamID])) {
+        return -ERESTARTSYS;
+    }
+
+    busy = get_filled_buffer(ar,StreamID);
+    while (!arRaw->read_buffer_available[StreamID]) {
+        up(&arRaw->raw_htc_read_sem[StreamID]);
+
+        /* Wait for the data */
+        AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Sleeping StreamID(%d) read process\n", StreamID));
+        if (wait_event_interruptible(arRaw->raw_htc_read_queue[StreamID],
+                                     arRaw->read_buffer_available[StreamID]))
+        {
+            return -EINTR;
+        }
+        if (down_interruptible(&arRaw->raw_htc_read_sem[StreamID])) {
+            return -ERESTARTSYS;
+        }
+        busy = get_filled_buffer(ar,StreamID);
+    }
+
+    /* Read the data */
+    readPtr = busy->currPtr;
+    if (length > busy->length - HTC_HEADER_LEN) {
+        length = busy->length - HTC_HEADER_LEN;
+    }
+    if (copy_to_user(buffer, &busy->data[readPtr], length)) {
+        up(&arRaw->raw_htc_read_sem[StreamID]);
+        return -EFAULT;
+    }
+
+    busy->currPtr += length;
+        
+    if (busy->currPtr == busy->length)
+    {    
+        busy->currPtr = 0;
+        busy->length = 0;        
+        HTC_PACKET_RESET_RX(&busy->HTCPacket);                                          
+        //AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("raw read ioctl:  ep for packet:%d \n", busy->HTCPacket.Endpoint));
+        HTCAddReceivePkt(ar->arHtcTarget, &busy->HTCPacket);
+    }
+    arRaw->read_buffer_available[StreamID] = FALSE;
+    up(&arRaw->raw_htc_read_sem[StreamID]);
+
+    return length;
+}
+
+static raw_htc_buffer *
+get_free_buffer(AR_SOFTC_T *ar, HTC_ENDPOINT_ID StreamID)
+{
+    int count;
+    raw_htc_buffer *free;
+    AR_RAW_HTC_T *arRaw = ar->arRawHtc;
+
+    free = NULL;
+    for (count = 0; count < RAW_HTC_WRITE_BUFFERS_NUM; count ++) {
+        free = &arRaw->raw_htc_write_buffer[StreamID][count];
+        if (free->length == 0) {
+            break;
+        }
+    }
+    if (!free->length) {
+        arRaw->write_buffer_available[StreamID] = TRUE;
+    } else {
+        arRaw->write_buffer_available[StreamID] = FALSE;
+    }
+
+    return free;
+}
+
+ssize_t ar6000_htc_raw_write(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID,
+                     char __user *buffer, size_t length)
+{
+    int writePtr;
+    raw_htc_buffer *free;
+    AR_RAW_HTC_T *arRaw = ar->arRawHtc;
+    if (arRawStream2EndpointID(ar,StreamID) == 0) {
+        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("StreamID(%d) not connected! \n", StreamID));
+        return -EFAULT;    
+    }
+    
+    if (down_interruptible(&arRaw->raw_htc_write_sem[StreamID])) {
+        return -ERESTARTSYS;
+    }
+
+    /* Search for a free buffer */
+    free = get_free_buffer(ar,StreamID);
+
+    /* Check if there is space to write else wait */
+    while (!arRaw->write_buffer_available[StreamID]) {
+        up(&arRaw->raw_htc_write_sem[StreamID]);
+
+        /* Wait for buffer to become free */
+        AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Sleeping StreamID(%d) write process\n", StreamID));
+        if (wait_event_interruptible(arRaw->raw_htc_write_queue[StreamID],
+                                     arRaw->write_buffer_available[StreamID]))
+        {
+            return -EINTR;
+        }
+        if (down_interruptible(&arRaw->raw_htc_write_sem[StreamID])) {
+            return -ERESTARTSYS;
+        }
+        free = get_free_buffer(ar,StreamID);
+    }
+
+    /* Send the data */
+    writePtr = HTC_HEADER_LEN;
+    if (length > (HTC_RAW_BUFFER_SIZE - HTC_HEADER_LEN)) {
+        length = HTC_RAW_BUFFER_SIZE - HTC_HEADER_LEN;
+    }
+
+    if (copy_from_user(&free->data[writePtr], buffer, length)) {
+        up(&arRaw->raw_htc_read_sem[StreamID]);
+        return -EFAULT;
+    }
+
+    free->length = length;
+        
+    SET_HTC_PACKET_INFO_TX(&free->HTCPacket,
+                           free,
+                           &free->data[writePtr],
+                           length,
+                           arRawStream2EndpointID(ar,StreamID),
+                           AR6K_DATA_PKT_TAG);
+    
+    HTCSendPkt(ar->arHtcTarget,&free->HTCPacket);
+    
+    arRaw->write_buffer_available[StreamID] = FALSE;
+    up(&arRaw->raw_htc_write_sem[StreamID]);
+
+    return length;
+}
+#endif /* HTC_RAW_INTERFACE */