diff options
Diffstat (limited to 'drivers/staging/otus/wwrap.c')
-rw-r--r-- | drivers/staging/otus/wwrap.c | 1207 |
1 files changed, 1207 insertions, 0 deletions
diff --git a/drivers/staging/otus/wwrap.c b/drivers/staging/otus/wwrap.c new file mode 100644 index 00000000000..a8729dfb6e6 --- /dev/null +++ b/drivers/staging/otus/wwrap.c @@ -0,0 +1,1207 @@ +/* + * Copyright (c) 2007-2008 Atheros Communications Inc. + * + * 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. + */ +/* Module Name : wwrap.c */ +/* Abstract */ +/* This module contains wrapper functions. */ +/* */ +/* NOTES */ +/* Platform dependent. */ +/* */ + +/* Please include your header files here */ +#include "oal_dt.h" +#include "usbdrv.h" + +#include <linux/netlink.h> + +#if WIRELESS_EXT > 12 +#include <net/iw_handler.h> +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#define URB_ZERO_PACKET USB_ZERO_PACKET +#endif + +extern void zfiRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); +extern void zfCoreRecv(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); +extern void zfIdlChkRsp(zdev_t* dev, u32_t* rsp, u16_t rspLen); +extern void zfIdlRsp(zdev_t* dev, u32_t *rsp, u16_t rspLen); + + + +//extern struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER]; +extern struct zsVapStruct vap[ZM_VAP_PORT_NUMBER]; + +u32_t zfLnxUsbSubmitTxData(zdev_t* dev); +u32_t zfLnxUsbIn(zdev_t* dev, urb_t *urb, zbuf_t *buf); +u32_t zfLnxSubmitRegInUrb(zdev_t *dev); +u32_t zfLnxUsbSubmitBulkUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction, + void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context); +u32_t zfLnxUsbSubmitIntUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction, + void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context, + u32_t interval); + +u16_t zfLnxGetFreeTxUrb(zdev_t *dev) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + u16_t idx; + unsigned long irqFlag; + + spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + + //idx = ((macp->TxUrbTail + 1) & (ZM_MAX_TX_URB_NUM - 1)); + + //if (idx != macp->TxUrbHead) + if (macp->TxUrbCnt != 0) + { + idx = macp->TxUrbTail; + macp->TxUrbTail = ((macp->TxUrbTail + 1) & (ZM_MAX_TX_URB_NUM - 1)); + macp->TxUrbCnt--; + } + else + { + //printk(KERN_ERR "macp->TxUrbCnt: %d\n", macp->TxUrbCnt); + idx = 0xffff; + } + + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return idx; +} + +void zfLnxPutTxUrb(zdev_t *dev) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + u16_t idx; + unsigned long irqFlag; + + spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + + idx = ((macp->TxUrbHead + 1) & (ZM_MAX_TX_URB_NUM - 1)); + + //if (idx != macp->TxUrbTail) + if (macp->TxUrbCnt < ZM_MAX_TX_URB_NUM) + { + macp->TxUrbHead = idx; + macp->TxUrbCnt++; + } + else + { + printk("UsbTxUrbQ inconsistent: TxUrbHead: %d, TxUrbTail: %d\n", + macp->TxUrbHead, macp->TxUrbTail); + } + + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); +} + +u16_t zfLnxCheckTxBufferCnt(zdev_t *dev) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + u16_t TxBufCnt; + unsigned long irqFlag; + + spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + + TxBufCnt = macp->TxBufCnt; + + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return TxBufCnt; +} + +UsbTxQ_t *zfLnxGetUsbTxBuffer(zdev_t *dev) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + u16_t idx; + UsbTxQ_t *TxQ; + unsigned long irqFlag; + + spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + + idx = ((macp->TxBufHead+1) & (ZM_MAX_TX_BUF_NUM - 1)); + + //if (idx != macp->TxBufTail) + if (macp->TxBufCnt > 0) + { + //printk("CWY - zfwGetUsbTxBuffer ,macp->TxBufCnt = %d\n", macp->TxBufCnt); + TxQ = (UsbTxQ_t *)&(macp->UsbTxBufQ[macp->TxBufHead]); + macp->TxBufHead = ((macp->TxBufHead+1) & (ZM_MAX_TX_BUF_NUM - 1)); + macp->TxBufCnt--; + } + else + { + if (macp->TxBufHead != macp->TxBufTail) + { + printk(KERN_ERR "zfwGetUsbTxBuf UsbTxBufQ inconsistent: TxBufHead: %d, TxBufTail: %d\n", + macp->TxBufHead, macp->TxBufTail); + } + + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return NULL; + } + + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return TxQ; +} + +u16_t zfLnxPutUsbTxBuffer(zdev_t *dev, u8_t *hdr, u16_t hdrlen, + u8_t *snap, u16_t snapLen, u8_t *tail, u16_t tailLen, + zbuf_t *buf, u16_t offset) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + u16_t idx; + UsbTxQ_t *TxQ; + unsigned long irqFlag; + + spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + + idx = ((macp->TxBufTail+1) & (ZM_MAX_TX_BUF_NUM - 1)); + + /* For Tx debug */ + //zm_assert(macp->TxBufCnt >= 0); // deleted because of always true + + //if (idx != macp->TxBufHead) + if (macp->TxBufCnt < ZM_MAX_TX_BUF_NUM) + { + //printk("CWY - zfwPutUsbTxBuffer ,macp->TxBufCnt = %d\n", macp->TxBufCnt); + TxQ = (UsbTxQ_t *)&(macp->UsbTxBufQ[macp->TxBufTail]); + memcpy(TxQ->hdr, hdr, hdrlen); + TxQ->hdrlen = hdrlen; + memcpy(TxQ->snap, snap, snapLen); + TxQ->snapLen = snapLen; + memcpy(TxQ->tail, tail, tailLen); + TxQ->tailLen = tailLen; + TxQ->buf = buf; + TxQ->offset = offset; + + macp->TxBufTail = ((macp->TxBufTail+1) & (ZM_MAX_TX_BUF_NUM - 1)); + macp->TxBufCnt++; + } + else + { + printk(KERN_ERR "zfLnxPutUsbTxBuffer UsbTxBufQ inconsistent: TxBufHead: %d, TxBufTail: %d, TxBufCnt: %d\n", + macp->TxBufHead, macp->TxBufTail, macp->TxBufCnt); + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return 0xffff; + } + + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return 0; +} + +zbuf_t *zfLnxGetUsbRxBuffer(zdev_t *dev) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + //u16_t idx; + zbuf_t *buf; + unsigned long irqFlag; + + spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + + //idx = ((macp->RxBufHead+1) & (ZM_MAX_RX_URB_NUM - 1)); + + //if (idx != macp->RxBufTail) + if (macp->RxBufCnt != 0) + { + buf = macp->UsbRxBufQ[macp->RxBufHead]; + macp->RxBufHead = ((macp->RxBufHead+1) & (ZM_MAX_RX_URB_NUM - 1)); + macp->RxBufCnt--; + } + else + { + printk("RxBufQ inconsistent: RxBufHead: %d, RxBufTail: %d\n", + macp->RxBufHead, macp->RxBufTail); + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return NULL; + } + + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return buf; +} + +u32_t zfLnxPutUsbRxBuffer(zdev_t *dev, zbuf_t *buf) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + u16_t idx; + unsigned long irqFlag; + + spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + + idx = ((macp->RxBufTail+1) & (ZM_MAX_RX_URB_NUM - 1)); + + //if (idx != macp->RxBufHead) + if (macp->RxBufCnt != ZM_MAX_RX_URB_NUM) + { + macp->UsbRxBufQ[macp->RxBufTail] = buf; + macp->RxBufTail = idx; + macp->RxBufCnt++; + } + else + { + printk("RxBufQ inconsistent: RxBufHead: %d, RxBufTail: %d\n", + macp->RxBufHead, macp->RxBufTail); + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return 0xffff; + } + + spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); + return 0; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +void zfLnxUsbDataOut_callback(urb_t *urb) +#else +void zfLnxUsbDataOut_callback(urb_t *urb, struct pt_regs *regs) +#endif +{ + zdev_t* dev = urb->context; + //UsbTxQ_t *TxData; + + /* Give the urb back */ + zfLnxPutTxUrb(dev); + + /* Check whether there is any pending buffer needed */ + /* to be sent */ + if (zfLnxCheckTxBufferCnt(dev) != 0) + { + //TxData = zfwGetUsbTxBuffer(dev); + + //if (TxData == NULL) + //{ + // printk("Get a NULL buffer from zfwGetUsbTxBuffer\n"); + // return; + //} + //else + //{ + zfLnxUsbSubmitTxData(dev); + //} + } +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +void zfLnxUsbDataIn_callback(urb_t *urb) +#else +void zfLnxUsbDataIn_callback(urb_t *urb, struct pt_regs *regs) +#endif +{ + zdev_t* dev = urb->context; + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + zbuf_t *buf; + zbuf_t *new_buf; + int status; + +#if ZM_USB_STREAM_MODE == 1 + static int remain_len = 0, check_pad = 0, check_len = 0; + int index = 0; + int chk_idx; + u16_t pkt_len; + u16_t pkt_tag; + u16_t ii; + zbuf_t *rxBufPool[8]; + u16_t rxBufPoolIndex = 0; +#endif + + /* Check status for URB */ + if (urb->status != 0){ + printk("zfLnxUsbDataIn_callback() : status=0x%x\n", urb->status); + if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET) + && (urb->status != -ESHUTDOWN)) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + if (urb->status == USB_ST_INTERNALERROR) + status = -1; + #else + if (urb->status == -EPIPE){ + //printk(KERN_ERR "nonzero read bulk status received: -EPIPE"); + status = -1; + } + + if (urb->status == -EPROTO){ + //printk(KERN_ERR "nonzero read bulk status received: -EPROTO"); + status = -1; + } + #endif + } + + //printk(KERN_ERR "urb->status: 0x%08x\n", urb->status); + + /* Dequeue skb buffer */ + buf = zfLnxGetUsbRxBuffer(dev); + dev_kfree_skb_any(buf); + #if 0 + /* Enqueue skb buffer */ + zfLnxPutUsbRxBuffer(dev, buf); + + /* Submit a Rx urb */ + zfLnxUsbIn(dev, urb, buf); + #endif + return; + } + + if (urb->actual_length == 0) + { + printk(KERN_ERR "Get an URB whose length is zero"); + status = -1; + } + + /* Dequeue skb buffer */ + buf = zfLnxGetUsbRxBuffer(dev); + + //zfwBufSetSize(dev, buf, urb->actual_length); +#ifdef NET_SKBUFF_DATA_USES_OFFSET + buf->tail = 0; + buf->len = 0; +#else + buf->tail = buf->data; + buf->len = 0; +#endif + + if ((buf->tail + urb->actual_length) > buf->end) + BUG(); + + skb_put(buf, urb->actual_length); + +#if ZM_USB_STREAM_MODE == 1 + if (remain_len != 0) + { + zbuf_t *remain_buf = macp->reamin_buf; + + index = remain_len; + remain_len -= check_pad; + + /* Copy data */ + memcpy(&(remain_buf->data[check_len]), buf->data, remain_len); + check_len += remain_len; + remain_len = 0; + + rxBufPool[rxBufPoolIndex++] = remain_buf; + } + + while(index < urb->actual_length) + { + pkt_len = buf->data[index] + (buf->data[index+1] << 8); + pkt_tag = buf->data[index+2] + (buf->data[index+3] << 8); + + if (pkt_tag == 0x4e00) + { + int pad_len; + + //printk("Get a packet, index: %d, pkt_len: 0x%04x\n", index, pkt_len); + #if 0 + /* Dump data */ + for (ii = index; ii < pkt_len+4;) + { + printk("%02x ", (buf->data[ii] & 0xff)); + + if ((++ii % 16) == 0) + printk("\n"); + } + + printk("\n"); + #endif + + pad_len = 4 - (pkt_len & 0x3); + + if(pad_len == 4) + pad_len = 0; + + chk_idx = index; + index = index + 4 + pkt_len + pad_len; + + if (index > ZM_MAX_RX_BUFFER_SIZE) + { + remain_len = index - ZM_MAX_RX_BUFFER_SIZE; // - pad_len; + check_len = ZM_MAX_RX_BUFFER_SIZE - chk_idx - 4; + check_pad = pad_len; + + /* Allocate a skb buffer */ + //new_buf = zfwBufAllocate(dev, ZM_MAX_RX_BUFFER_SIZE); + new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); + + /* Set skb buffer length */ + #ifdef NET_SKBUFF_DATA_USES_OFFSET + new_buf->tail = 0; + new_buf->len = 0; + #else + new_buf->tail = new_buf->data; + new_buf->len = 0; + #endif + + skb_put(new_buf, pkt_len); + + /* Copy the buffer */ + memcpy(new_buf->data, &(buf->data[chk_idx+4]), check_len); + + /* Record the buffer pointer */ + macp->reamin_buf = new_buf; + } + else + { + #ifdef ZM_DONT_COPY_RX_BUFFER + if (rxBufPoolIndex == 0) + { + new_buf = skb_clone(buf, GFP_ATOMIC); + + new_buf->data = &(buf->data[chk_idx+4]); + new_buf->len = pkt_len; + } + else + { + #endif + /* Allocate a skb buffer */ + new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); + + /* Set skb buffer length */ + #ifdef NET_SKBUFF_DATA_USES_OFFSET + new_buf->tail = 0; + new_buf->len = 0; + #else + new_buf->tail = new_buf->data; + new_buf->len = 0; + #endif + + skb_put(new_buf, pkt_len); + + /* Copy the buffer */ + memcpy(new_buf->data, &(buf->data[chk_idx+4]), pkt_len); + + #ifdef ZM_DONT_COPY_RX_BUFFER + } + #endif + rxBufPool[rxBufPoolIndex++] = new_buf; + } + } + else + { + printk(KERN_ERR "Can't find tag, pkt_len: 0x%04x, tag: 0x%04x\n", pkt_len, pkt_tag); + + /* Free buffer */ + dev_kfree_skb_any(buf); + + /* Allocate a skb buffer */ + new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); + + /* Enqueue skb buffer */ + zfLnxPutUsbRxBuffer(dev, new_buf); + + /* Submit a Rx urb */ + zfLnxUsbIn(dev, urb, new_buf); + + return; + } + } + + /* Free buffer */ + dev_kfree_skb_any(buf); +#endif + + /* Allocate a skb buffer */ + new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); + + /* Enqueue skb buffer */ + zfLnxPutUsbRxBuffer(dev, new_buf); + + /* Submit a Rx urb */ + zfLnxUsbIn(dev, urb, new_buf); + +#if ZM_USB_STREAM_MODE == 1 + for(ii = 0; ii < rxBufPoolIndex; ii++) + { + macp->usbCbFunctions.zfcbUsbRecv(dev, rxBufPool[ii]); + } +#else + /* pass data to upper layer */ + macp->usbCbFunctions.zfcbUsbRecv(dev, buf); +#endif +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +void zfLnxUsbRegOut_callback(urb_t *urb) +#else +void zfLnxUsbRegOut_callback(urb_t *urb, struct pt_regs *regs) +#endif +{ + //dev_t* dev = urb->context; + + //printk(KERN_ERR "zfwUsbRegOut_callback\n"); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +void zfLnxUsbRegIn_callback(urb_t *urb) +#else +void zfLnxUsbRegIn_callback(urb_t *urb, struct pt_regs *regs) +#endif +{ + zdev_t* dev = urb->context; + u32_t rsp[64/4]; + int status; + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + + /* Check status for URB */ + if (urb->status != 0){ + printk("zfLnxUsbRegIn_callback() : status=0x%x\n", urb->status); + if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET) + && (urb->status != -ESHUTDOWN)) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + if (urb->status == USB_ST_INTERNALERROR) + status = -1; + #else + if (urb->status == -EPIPE){ + //printk(KERN_ERR "nonzero read bulk status received: -EPIPE"); + status = -1; + } + + if (urb->status == -EPROTO){ + //printk(KERN_ERR "nonzero read bulk status received: -EPROTO"); + status = -1; + } + #endif + } + + //printk(KERN_ERR "urb->status: 0x%08x\n", urb->status); + return; + } + + if (urb->actual_length == 0) + { + printk(KERN_ERR "Get an URB whose length is zero"); + status = -1; + } + + /* Copy data into respone buffer */ + memcpy(rsp, macp->regUsbReadBuf, urb->actual_length); + + /* Notify to upper layer */ + //zfIdlChkRsp(dev, rsp, (u16_t)urb->actual_length); + //zfiUsbRegIn(dev, rsp, (u16_t)urb->actual_length); + macp->usbCbFunctions.zfcbUsbRegIn(dev, rsp, (u16_t)urb->actual_length); + + /* Issue another USB IN URB */ + zfLnxSubmitRegInUrb(dev); +} + +u32_t zfLnxSubmitRegInUrb(zdev_t *dev) +{ + u32_t ret; + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + + /* Submit a rx urb */ + //ret = zfLnxUsbSubmitBulkUrb(macp->RegInUrb, macp->udev, + // USB_REG_IN_PIPE, USB_DIR_IN, macp->regUsbReadBuf, + // ZM_USB_REG_MAX_BUF_SIZE, zfLnxUsbRegIn_callback, dev); + //CWYang(-) + //if (ret != 0) + // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret); + + ret = zfLnxUsbSubmitIntUrb(macp->RegInUrb, macp->udev, + USB_REG_IN_PIPE, USB_DIR_IN, macp->regUsbReadBuf, + ZM_USB_REG_MAX_BUF_SIZE, zfLnxUsbRegIn_callback, dev, 1); + + return ret; +} + +u32_t zfLnxUsbSubmitTxData(zdev_t* dev) +{ + u32_t i; + u32_t ret; + u16_t freeTxUrb; + u8_t *puTxBuf = NULL; + UsbTxQ_t *TxData; + int len = 0; + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; +#if ZM_USB_TX_STREAM_MODE == 1 + u8_t ii; + u16_t offset = 0; + u16_t usbTxAggCnt; + u16_t *pUsbTxHdr; + UsbTxQ_t *TxQPool[ZM_MAX_TX_AGGREGATE_NUM]; +#endif + + /* First check whether there is a free URB */ + freeTxUrb = zfLnxGetFreeTxUrb(dev); + + /* If there is no any free Tx Urb */ + if (freeTxUrb == 0xffff) + { + //printk(KERN_ERR "Can't get free Tx Urb\n"); + //printk("CWY - Can't get free Tx Urb\n"); + return 0xffff; + } + +#if ZM_USB_TX_STREAM_MODE == 1 + usbTxAggCnt = zfLnxCheckTxBufferCnt(dev); + + if (usbTxAggCnt >= ZM_MAX_TX_AGGREGATE_NUM) + { + usbTxAggCnt = ZM_MAX_TX_AGGREGATE_NUM; + } + else + { + usbTxAggCnt = 1; + } + + //printk("usbTxAggCnt: %d\n", usbTxAggCnt); +#endif + +#if ZM_USB_TX_STREAM_MODE == 1 + for(ii = 0; ii < usbTxAggCnt; ii++) + { +#endif + /* Dequeue the packet from UsbTxBufQ */ + TxData = zfLnxGetUsbTxBuffer(dev); + if (TxData == NULL) + { + /* Give the urb back */ + zfLnxPutTxUrb(dev); + return 0xffff; + } + + /* Point to the freeTxUrb buffer */ + puTxBuf = macp->txUsbBuf[freeTxUrb]; + +#if ZM_USB_TX_STREAM_MODE == 1 + puTxBuf += offset; + pUsbTxHdr = (u16_t *)puTxBuf; + + /* Add the packet length and tag information */ + *pUsbTxHdr++ = TxData->hdrlen + TxData->snapLen + + (TxData->buf->len - TxData->offset) + TxData->tailLen; + + *pUsbTxHdr++ = 0x697e; + + puTxBuf += 4; +#endif // #ifdef ZM_USB_TX_STREAM_MODE + + /* Copy WLAN header and packet buffer into USB buffer */ + for(i = 0; i < TxData->hdrlen; i++) + { + *puTxBuf++ = TxData->hdr[i]; + } + + /* Copy SNAP header */ + for(i = 0; i < TxData->snapLen; i++) + { + *puTxBuf++ = TxData->snap[i]; + } + + /* Copy packet buffer */ + for(i = 0; i < TxData->buf->len - TxData->offset; i++) + { + //*puTxBuf++ = zmw_rx_buf_readb(dev, TxData->buf, i); + *puTxBuf++ = *(u8_t*)((u8_t*)TxData->buf->data+i+TxData->offset); + } + + /* Copy tail */ + for(i = 0; i < TxData->tailLen; i++) + { + *puTxBuf++ = TxData->tail[i]; + } + + len = TxData->hdrlen+TxData->snapLen+TxData->buf->len+TxData->tailLen-TxData->offset; + + #if 0 + if (TxData->hdrlen != 0) + { + puTxBuf = macp->txUsbBuf[freeTxUrb]; + for (i = 0; i < len; i++) + { + printk("%02x ", puTxBuf[i]); + if (i % 16 == 15) + printk("\n"); + } + printk("\n"); + } + #endif + #if 0 + /* For debug purpose */ + if(TxData->hdr[9] & 0x40) + { + int i; + u16_t ctrlLen = TxData->hdr[0] + (TxData->hdr[1] << 8); + + if (ctrlLen != len + 4) + { + /* Dump control setting */ + for(i = 0; i < 8; i++) + { + printk(KERN_ERR "0x%02x ", TxData->hdr[i]); + } + printk(KERN_ERR "\n"); + + printk(KERN_ERR "ctrLen: %d, hdrLen: %d, snapLen: %d\n", ctrlLen, TxData->hdrlen, TxData->snapLen); + printk(KERN_ERR "bufLen: %d, tailLen: %d, len: %d\n", TxData->buf->len, TxData->tailLen, len); + } + } + #endif + +#if ZM_USB_TX_STREAM_MODE == 1 + // Add the Length and Tag + len += 4; + + //printk("%d packet, length: %d\n", ii+1, len); + + if (ii < (ZM_MAX_TX_AGGREGATE_NUM-1)) + { + /* Pad the buffer to firmware descriptor boundary */ + offset += (((len-1) / 4) + 1) * 4; + } + + if (ii == (ZM_MAX_TX_AGGREGATE_NUM-1)) + { + len += offset; + } + + TxQPool[ii] = TxData; + + //DbgPrint("%d packet, offset: %d\n", ii+1, pUsbTxTransfer->offset); + + /* free packet */ + //zfBufFree(dev, txData->buf); + } +#endif + //printk("CWY - call zfwUsbSubmitBulkUrb(), len = 0x%d\n", len); + /* Submit a tx urb */ + ret = zfLnxUsbSubmitBulkUrb(macp->WlanTxDataUrb[freeTxUrb], macp->udev, + USB_WLAN_TX_PIPE, USB_DIR_OUT, macp->txUsbBuf[freeTxUrb], + len, zfLnxUsbDataOut_callback, dev); + //CWYang(-) + //if (ret != 0) + // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret); + + /* free packet */ + //dev_kfree_skb_any(TxData->buf); +#if ZM_USB_TX_STREAM_MODE == 1 + for(ii = 0; ii < usbTxAggCnt; ii++) + macp->usbCbFunctions.zfcbUsbOutComplete(dev, TxQPool[ii]->buf, 1, TxQPool[ii]->hdr); +#else + macp->usbCbFunctions.zfcbUsbOutComplete(dev, TxData->buf, 1, TxData->hdr); +#endif + + return ret; +} + + + +u32_t zfLnxUsbIn(zdev_t* dev, urb_t *urb, zbuf_t *buf) +{ + u32_t ret; + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + + /* Submit a rx urb */ + ret = zfLnxUsbSubmitBulkUrb(urb, macp->udev, USB_WLAN_RX_PIPE, + USB_DIR_IN, buf->data, ZM_MAX_RX_BUFFER_SIZE, + zfLnxUsbDataIn_callback, dev); + //CWYang(-) + //if (ret != 0) + // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret); + + return ret; +} + +u32_t zfLnxUsbWriteReg(zdev_t* dev, u32_t* cmd, u16_t cmdLen) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + u32_t ret; + +#ifdef ZM_CONFIG_BIG_ENDIAN + int ii = 0; + + for(ii=0; ii<(cmdLen>>2); ii++) + cmd[ii] = cpu_to_le32(cmd[ii]); +#endif + + memcpy(macp->regUsbWriteBuf, cmd, cmdLen); + + /* Issue an USB Out transfer */ + /* Submit a tx urb */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + ret = zfLnxUsbSubmitBulkUrb(macp->RegOutUrb, macp->udev, + USB_REG_OUT_PIPE, USB_DIR_OUT, macp->regUsbWriteBuf, + cmdLen, zfLnxUsbRegOut_callback, dev); +#else + ret = zfLnxUsbSubmitIntUrb(macp->RegOutUrb, macp->udev, + USB_REG_OUT_PIPE, USB_DIR_OUT, macp->regUsbWriteBuf, + cmdLen, zfLnxUsbRegOut_callback, dev, 1); +#endif + + return ret; +} + + +u32_t zfLnxUsbOut(zdev_t* dev, u8_t *hdr, u16_t hdrlen, u8_t *snap, u16_t snapLen, + u8_t *tail, u16_t tailLen, zbuf_t *buf, u16_t offset) +{ + u32_t ret; + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + + /* Check length of tail buffer */ + //zm_assert((tailLen <= 16)); + + /* Enqueue the packet into UsbTxBufQ */ + if (zfLnxPutUsbTxBuffer(dev, hdr, hdrlen, snap, snapLen, tail, tailLen, buf, offset) == 0xffff) + { + /* free packet */ + //printk("CWY - zfwPutUsbTxBuffer Error, free packet\n"); + //dev_kfree_skb_any(buf); + macp->usbCbFunctions.zfcbUsbOutComplete(dev, buf, 0, hdr); + return 0xffff; + } + + //return 0; + //printk("CWY - call zfwUsbSubmitTxData()\n"); + ret = zfLnxUsbSubmitTxData(dev); + return ret; +} + +void zfLnxInitUsbTxQ(zdev_t* dev) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + + printk(KERN_ERR "zfwInitUsbTxQ\n"); + + /* Zero memory for UsbTxBufQ */ + memset(macp->UsbTxBufQ, 0, sizeof(UsbTxQ_t) * ZM_MAX_TX_URB_NUM); + + macp->TxBufHead = 0; + macp->TxBufTail = 0; + macp->TxUrbHead = 0; + macp->TxUrbTail = 0; + macp->TxUrbCnt = ZM_MAX_TX_URB_NUM; +} + +void zfLnxInitUsbRxQ(zdev_t* dev) +{ + u16_t i; + zbuf_t *buf; + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + + /* Zero memory for UsbRxBufQ */ + memset(macp->UsbRxBufQ, 0, sizeof(zbuf_t *) * ZM_MAX_RX_URB_NUM); + + macp->RxBufHead = 0; + + for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) + { + //buf = zfwBufAllocate(dev, ZM_MAX_RX_BUFFER_SIZE); + buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); + macp->UsbRxBufQ[i] = buf; + } + + //macp->RxBufTail = ZM_MAX_RX_URB_NUM - 1; + macp->RxBufTail = 0; + + /* Submit all Rx urbs */ + for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) + { + zfLnxPutUsbRxBuffer(dev, macp->UsbRxBufQ[i]); + zfLnxUsbIn(dev, macp->WlanRxDataUrb[i], macp->UsbRxBufQ[i]); + } +} + + + +u32_t zfLnxUsbSubmitBulkUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction, + void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context) +{ + u32_t ret; + + if(direction == USB_DIR_OUT) + { + usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, epnum), + transfer_buffer, buffer_length, complete, context); + + urb->transfer_flags |= URB_ZERO_PACKET; + } + else + { + usb_fill_bulk_urb(urb, usb, usb_rcvbulkpipe(usb, epnum), + transfer_buffer, buffer_length, complete, context); + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + + if (epnum == 4) + { + if (urb->hcpriv) + { + //printk("CWY - urb->hcpriv set by unknown reason, reset it\n"); + //urb->hcpriv = 0; + } + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + ret = usb_submit_urb(urb, GFP_ATOMIC); +#else + ret = usb_submit_urb(urb); +#endif + if ((epnum == 4) & (ret != 0)) + { + //printk("CWY - ret = %x\n", ret); + } + return ret; +} + +u32_t zfLnxUsbSubmitIntUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction, + void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context, + u32_t interval) +{ + u32_t ret; + + if(direction == USB_DIR_OUT) + { + usb_fill_int_urb(urb, usb, usb_sndbulkpipe(usb, epnum), + transfer_buffer, buffer_length, complete, context, interval); + } + else + { + usb_fill_int_urb(urb, usb, usb_rcvbulkpipe(usb, epnum), + transfer_buffer, buffer_length, complete, context, interval); + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + ret = usb_submit_urb(urb, GFP_ATOMIC); +#else + ret = usb_submit_urb(urb); +#endif + + return ret; +} + +#ifdef ZM_ENABLE_CENC +int zfLnxCencSendMsg(struct sock *netlink_sk, u_int8_t *msg, int len) +{ +#define COMMTYPE_GROUP 8 +#define WAI_K_MSG 0x11 + + int ret = -1; + int size; + unsigned char *old_tail; + struct sk_buff *skb; + struct nlmsghdr *nlh; + char *pos = NULL; + + size = NLMSG_SPACE(len); + skb = alloc_skb(size, GFP_ATOMIC); + + if(skb == NULL) + { + printk("dev_alloc_skb failure \n"); + goto out; + } + old_tail = skb->tail; + + /*填写数据报相关信息*/ + nlh = NLMSG_PUT(skb, 0, 0, WAI_K_MSG, size-sizeof(*nlh)); + pos = NLMSG_DATA(nlh); + memset(pos, 0, len); + + /*传输到用户空间的数据*/ + memcpy(pos, msg, len); + /*计算经过字节对其后的数据实际长度*/ + nlh->nlmsg_len = skb->tail - old_tail; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) + NETLINK_CB(skb).dst_groups = COMMTYPE_GROUP; +#else + NETLINK_CB(skb).dst_group = COMMTYPE_GROUP; +#endif + netlink_broadcast(netlink_sk, skb, 0, COMMTYPE_GROUP, GFP_ATOMIC); + ret = 0; +out: + return ret; +nlmsg_failure: /*NLMSG_PUT 失败,则撤销套接字缓存*/ + if(skb) + kfree_skb(skb); + goto out; + +#undef COMMTYPE_GROUP +#undef WAI_K_MSG +} +#endif //ZM_ENABLE_CENC + +/* Simply return 0xffff if VAP function is not supported */ +u16_t zfLnxGetVapId(zdev_t* dev) +{ + u16_t i; + + for (i=0; i<ZM_VAP_PORT_NUMBER; i++) + { + if (vap[i].dev == dev) + { + return i; + } + } + return 0xffff; +} + +u32_t zfwReadReg(zdev_t* dev, u32_t offset) +{ + return 0; +} + +#ifndef INIT_WORK +#define work_struct tq_struct + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#define schedule_work(a) queue_task(a, &tq_scheduler) +#else +#define schedule_work(a) schedule_task(a) +#endif + +#define flush_scheduled_work flush_scheduled_tasks +#define INIT_WORK(_wq, _routine, _data) INIT_TQUEUE(_wq, _routine, _data) +#define PREPARE_WORK(_wq, _routine, _data) PREPARE_TQUEUE(_wq, _routine, _data) +#endif + +#define KEVENT_WATCHDOG 0x00000001 + +u32_t smp_kevent_Lock = 0; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) +void kevent(struct work_struct *work) +#else +void kevent(void *data) +#endif +{ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + struct usbdrv_private *macp = + container_of(work, struct usbdrv_private, kevent); + zdev_t *dev = macp->device; +#else + zdev_t *dev = (zdev_t *) data; + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; +#endif + + if (macp == NULL) + { + return; + } + + if (test_and_set_bit(0, (void *)&smp_kevent_Lock)) + { + //schedule_work(&macp->kevent); + return; + } + + down(&macp->ioctl_sem); + + if (test_and_clear_bit(KEVENT_WATCHDOG, &macp->kevent_flags)) + { + extern u16_t zfHpStartRecv(zdev_t *dev); + //zfiHwWatchDogReinit(dev); + printk(("\n ************ Hw watchDog occur!! ************** \n")); + zfiWlanSuspend(dev); + zfiWlanResume(dev,0); + zfHpStartRecv(dev); + } + + clear_bit(0, (void *)&smp_kevent_Lock); + up(&macp->ioctl_sem); +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfLnxCreateThread */ +/* Create a Thread */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* */ +/* OUTPUTS */ +/* always 0 */ +/* */ +/* AUTHOR */ +/* Yuan-Gu Wei Atheros Communications, INC. 2007.3 */ +/* */ +/************************************************************************/ +u8_t zfLnxCreateThread(zdev_t *dev) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + + /* Create Mutex and keventd */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) + INIT_WORK(&macp->kevent, kevent, dev); +#else + INIT_WORK(&macp->kevent, kevent); +#endif + init_MUTEX(&macp->ioctl_sem); + + return 0; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfLnxSignalThread */ +/* Signal Thread with Flag */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* flag : signal thread flag */ +/* */ +/* OUTPUTS */ +/* none */ +/* */ +/* AUTHOR */ +/* Yuan-Gu Wei Atheros Communications, INC. 2007.3 */ +/* */ +/************************************************************************/ +void zfLnxSignalThread(zdev_t *dev, int flag) +{ + struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; + + if (macp == NULL) + { + printk("macp is NULL\n"); + return; + } + + if (0 && macp->kevent_ready != 1) + { + printk("Kevent not ready\n"); + return; + } + + set_bit(flag, &macp->kevent_flags); + + if (!schedule_work(&macp->kevent)) + { + //Fails is Normal + //printk(KERN_ERR "schedule_task failed, flag = %x\n", flag); + } +} + +/* Notify wrapper todo redownload firmware and reinit procedure when */ +/* hardware watchdog occur : zfiHwWatchDogReinit() */ +void zfLnxWatchDogNotify(zdev_t* dev) +{ + zfLnxSignalThread(dev, KEVENT_WATCHDOG); +} + +/* Query Durantion of Active Scan */ +void zfwGetActiveScanDur(zdev_t* dev, u8_t* Dur) +{ + *Dur = 30; // default 30 ms +} + +void zfwGetShowZeroLengthSSID(zdev_t* dev, u8_t* Dur) +{ + *Dur = 0; +} + |