update brcm-2.4 to 2.4.35.4, integrate new broadcom system code, update broadcom...
[openwrt/staging/mkresin.git] / package / broadcom-wl / src / driver / linux_osl.c
index 24fd77daea53c3f7bbfab50aa2b8f17b9f15a674..cc55eb68e9d37321a44c5ab8d77077c7ffb666b1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Linux OS Independent Layer
  *
- * Copyright 2006, Broadcom Corporation
+ * Copyright 2007, Broadcom Corporation
  * All Rights Reserved.
  * 
  * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
  * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
  * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
  *
- * $Id: linux_osl.c,v 1.1.1.14 2006/04/08 06:13:39 honor Exp $
+ * $Id$
  */
 
 #define LINUX_OSL
 
 #include <typedefs.h>
 #include <bcmendian.h>
-#include <linux/module.h>
 #include <linuxver.h>
 #include <bcmdefs.h>
 #include <osl.h>
 #include "linux_osl.h"
-#include <bcmutils.h>
+#include "bcmutils.h"
 #include <linux/delay.h>
 #ifdef mips
 #include <asm/paccess.h>
 #endif /* mips */
 #include <pcicfg.h>
 
-#define PCI_CFG_RETRY          10      
+#define PCI_CFG_RETRY          10
 
 #define OS_HANDLE_MAGIC                0x1234abcd      /* Magic # to recognise osh */
-#define BCM_MEM_FILENAME_LEN   24              /* Mem. filename length */
-
-typedef struct bcm_mem_link {
-       struct bcm_mem_link *prev;
-       struct bcm_mem_link *next;
-       uint    size;
-       int     line;
-       char    file[BCM_MEM_FILENAME_LEN];
+#define BCM_MEM_FILENAME_LEN   24      /* Mem. filename length */
+
+typedef struct bcm_mem_link
+{
+  struct bcm_mem_link *prev;
+  struct bcm_mem_link *next;
+  uint size;
+  int line;
+  char file[BCM_MEM_FILENAME_LEN];
 } bcm_mem_link_t;
 
-static int16 linuxbcmerrormap[] =  \
-{      0,                      /* 0 */
-       -EINVAL,                /* BCME_ERROR */
-       -EINVAL,                /* BCME_BADARG */
-       -EINVAL,                /* BCME_BADOPTION */
-       -EINVAL,                /* BCME_NOTUP */
-       -EINVAL,                /* BCME_NOTDOWN */
-       -EINVAL,                /* BCME_NOTAP */
-       -EINVAL,                /* BCME_NOTSTA */
-       -EINVAL,                /* BCME_BADKEYIDX */
-       -EINVAL,                /* BCME_RADIOOFF */
-       -EINVAL,                /* BCME_NOTBANDLOCKED */
-       -EINVAL,                /* BCME_NOCLK */
-       -EINVAL,                /* BCME_BADRATESET */
-       -EINVAL,                /* BCME_BADBAND */
-       -E2BIG,                 /* BCME_BUFTOOSHORT */
-       -E2BIG,                 /* BCME_BUFTOOLONG */
-       -EBUSY,                 /* BCME_BUSY */
-       -EINVAL,                /* BCME_NOTASSOCIATED */
-       -EINVAL,                /* BCME_BADSSIDLEN */
-       -EINVAL,                /* BCME_OUTOFRANGECHAN */
-       -EINVAL,                /* BCME_BADCHAN */
-       -EFAULT,                /* BCME_BADADDR */
-       -ENOMEM,                /* BCME_NORESOURCE */
-       -EOPNOTSUPP,            /* BCME_UNSUPPORTED */
-       -EMSGSIZE,              /* BCME_BADLENGTH */
-       -EINVAL,                /* BCME_NOTREADY */
-       -EPERM,                 /* BCME_NOTPERMITTED */
-       -ENOMEM,                /* BCME_NOMEM */
-       -EINVAL,                /* BCME_ASSOCIATED */
-       -ERANGE,                /* BCME_RANGE */
-       -EINVAL,                /* BCME_NOTFOUND */
-       -EINVAL,                /* BCME_WME_NOT_ENABLED */
-       -EINVAL,                /* BCME_TSPEC_NOTFOUND */
-       -EINVAL,                /* BCME_ACM_NOTSUPPORTED */
-       -EINVAL,                /* BCME_NOT_WME_ASSOCIATION */
-       -EIO,                   /* BCME_SDIO_ERROR */
-       -ENODEV                 /* BCME_DONGLE_DOWN */
+#if 0
+struct osl_info
+{
+  osl_pubinfo_t pub;
+  uint magic;
+  void *pdev;
+  uint malloced;
+  uint failed;
+  uint bustype;
+  bcm_mem_link_t *dbgmem_list;
+#ifdef BCMDBG_PKT              /* pkt logging for debugging */
+  pktlist_info_t pktlist;
+#endif                         /* BCMDBG_PKT */
+};
+#endif
+
+static int16 linuxbcmerrormap[] = { 0, /* 0 */
+  -EINVAL,                     /* BCME_ERROR */
+  -EINVAL,                     /* BCME_BADARG */
+  -EINVAL,                     /* BCME_BADOPTION */
+  -EINVAL,                     /* BCME_NOTUP */
+  -EINVAL,                     /* BCME_NOTDOWN */
+  -EINVAL,                     /* BCME_NOTAP */
+  -EINVAL,                     /* BCME_NOTSTA */
+  -EINVAL,                     /* BCME_BADKEYIDX */
+  -EINVAL,                     /* BCME_RADIOOFF */
+  -EINVAL,                     /* BCME_NOTBANDLOCKED */
+  -EINVAL,                     /* BCME_NOCLK */
+  -EINVAL,                     /* BCME_BADRATESET */
+  -EINVAL,                     /* BCME_BADBAND */
+  -E2BIG,                      /* BCME_BUFTOOSHORT */
+  -E2BIG,                      /* BCME_BUFTOOLONG */
+  -EBUSY,                      /* BCME_BUSY */
+  -EINVAL,                     /* BCME_NOTASSOCIATED */
+  -EINVAL,                     /* BCME_BADSSIDLEN */
+  -EINVAL,                     /* BCME_OUTOFRANGECHAN */
+  -EINVAL,                     /* BCME_BADCHAN */
+  -EFAULT,                     /* BCME_BADADDR */
+  -ENOMEM,                     /* BCME_NORESOURCE */
+  -EOPNOTSUPP,                 /* BCME_UNSUPPORTED */
+  -EMSGSIZE,                   /* BCME_BADLENGTH */
+  -EINVAL,                     /* BCME_NOTREADY */
+  -EPERM,                      /* BCME_NOTPERMITTED */
+  -ENOMEM,                     /* BCME_NOMEM */
+  -EINVAL,                     /* BCME_ASSOCIATED */
+  -ERANGE,                     /* BCME_RANGE */
+  -EINVAL,                     /* BCME_NOTFOUND */
+  -EINVAL,                     /* BCME_WME_NOT_ENABLED */
+  -EINVAL,                     /* BCME_TSPEC_NOTFOUND */
+  -EINVAL,                     /* BCME_ACM_NOTSUPPORTED */
+  -EINVAL,                     /* BCME_NOT_WME_ASSOCIATION */
+  -EIO,                                /* BCME_SDIO_ERROR */
+  -ENODEV,                     /* BCME_DONGLE_DOWN */
+  -EINVAL                      /* BCME_VERSION */
+/* When an new error code is added to bcmutils.h, add os 
+ * spcecific error translation here as well
+ */
+/* check if BCME_LAST changed since the last time this function was updated */
+#if BCME_LAST != -37
+#error "You need to add a OS error translation in the linuxbcmerrormap \
+       for new error code defined in bcmuitls.h"
+#endif /* BCME_LAST != -37 */
 };
 
 /* translate bcmerrors into linux errors */
 int
-osl_error(int bcmerror)
+osl_error (int bcmerror)
 {
-       int abs_bcmerror;
-       int array_size = ARRAYSIZE(linuxbcmerrormap);
+  if (bcmerror > 0)
+    bcmerror = 0;
+  else if (bcmerror < BCME_LAST)
+    bcmerror = BCME_ERROR;
 
-       abs_bcmerror = ABS(bcmerror);
+  /* Array bounds covered by ASSERT in osl_attach */
+  return linuxbcmerrormap[-bcmerror];
+}
 
-       if (bcmerror > 0)
-               abs_bcmerror = 0;
+osl_t *
+osl_attach (void *pdev, uint bustype, bool pkttag)
+{
+  osl_t *osh;
+
+  osh = kmalloc (sizeof (osl_t), GFP_ATOMIC);
+  ASSERT (osh);
+
+  bzero (osh, sizeof (osl_t));
+
+  /* Check that error map has the right number of entries in it */
+  ASSERT (ABS (BCME_LAST) == (ARRAYSIZE (linuxbcmerrormap) - 1));
+
+  osh->magic = OS_HANDLE_MAGIC;
+  osh->malloced = 0;
+  osh->failed = 0;
+  osh->dbgmem_list = NULL;
+  osh->pdev = pdev;
+  osh->pub.pkttag = pkttag;
+  osh->bustype = bustype;
+
+  switch (bustype)
+    {
+    case PCI_BUS:
+    case SB_BUS:
+    case PCMCIA_BUS:
+      osh->pub.mmbus = TRUE;
+      break;
+    case JTAG_BUS:
+    case SDIO_BUS:
+      break;
+    default:
+      ASSERT (FALSE);
+      break;
+    }
+
+#ifdef BCMDBG
+  if (pkttag)
+    {
+      struct sk_buff *skb;
+      ASSERT (OSL_PKTTAG_SZ <= sizeof (skb->cb));
+    }
+#endif
+  return osh;
+}
 
-       else if (abs_bcmerror >= array_size)
-               abs_bcmerror = BCME_ERROR;
+void
+osl_detach (osl_t * osh)
+{
+  if (osh == NULL)
+    return;
 
-       return linuxbcmerrormap[abs_bcmerror];
+  ASSERT (osh->magic == OS_HANDLE_MAGIC);
+  kfree (osh);
 }
 
-osl_t *
-osl_attach(void *pdev, bool pkttag)
+/* Return a new packet. zero out pkttag */
+void *
+osl_pktget (osl_t * osh, uint len)
+{
+  struct sk_buff *skb;
+
+  if ((skb = dev_alloc_skb (len)))
+    {
+      skb_put (skb, len);
+      skb->priority = 0;
+
+#ifdef BCMDBG_PKT
+      pktlist_add (&(osh->pktlist), (void *) skb);
+#endif /* BCMDBG_PKT */
+
+      osh->pub.pktalloced++;
+    }
+
+  return ((void *) skb);
+}
+
+/* Free the driver packet. Free the tag if present */
+void
+osl_pktfree (osl_t * osh, void *p, bool send)
+{
+  struct sk_buff *skb, *nskb;
+
+  skb = (struct sk_buff *) p;
+
+  if (send && osh->pub.tx_fn)
+    osh->pub.tx_fn (osh->pub.tx_ctx, p, 0);
+
+  /* perversion: we use skb->next to chain multi-skb packets */
+  while (skb)
+    {
+      nskb = skb->next;
+      skb->next = NULL;
+
+#ifdef BCMDBG_PKT
+      pktlist_remove (&(osh->pktlist), (void *) skb);
+#endif /* BCMDBG_PKT */
+
+      if (skb->destructor)
+       {
+         /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists
+          */
+         dev_kfree_skb_any (skb);
+       }
+      else
+       {
+         /* can free immediately (even in_irq()) if destructor does not exist */
+         dev_kfree_skb (skb);
+       }
+
+      osh->pub.pktalloced--;
+
+      skb = nskb;
+    }
+}
+
+uint32
+osl_pci_read_config (osl_t * osh, uint offset, uint size)
 {
-       osl_t *osh;
+  uint val;
+  uint retry = PCI_CFG_RETRY;
 
-       osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
-       ASSERT(osh);
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
 
-       bzero(osh, sizeof(osl_t));
+  /* only 4byte access supported */
+  ASSERT (size == 4);
 
-       /*
-        * check the cases where
-        * 1.Error code Added to bcmerror table, but forgot to add it to the OS
-        * dependent error code
-        * 2. Error code is added to the bcmerror table, but forgot to add the
-        * corresponding errorstring(dummy call to bcmerrorstr)
-        */
-       bcmerrorstr(0);
-       ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
+  do
+    {
+      pci_read_config_dword (osh->pdev, offset, &val);
+      if (val != 0xffffffff)
+       break;
+    }
+  while (retry--);
 
-       osh->magic = OS_HANDLE_MAGIC;
-       osh->malloced = 0;
-       osh->failed = 0;
-       osh->dbgmem_list = NULL;
-       osh->pdev = pdev;
-       osh->pub.pkttag = pkttag;
+#ifdef BCMDBG
+  if (retry < PCI_CFG_RETRY)
+    printk ("PCI CONFIG READ access to %d required %d retries\n", offset,
+           (PCI_CFG_RETRY - retry));
+#endif /* BCMDBG */
 
-       return osh;
+  return (val);
 }
 
 void
-osl_detach(osl_t *osh)
+osl_pci_write_config (osl_t * osh, uint offset, uint size, uint val)
 {
-       if (osh == NULL)
-               return;
+  uint retry = PCI_CFG_RETRY;
+
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
+
+  /* only 4byte access supported */
+  ASSERT (size == 4);
+
+  do
+    {
+      pci_write_config_dword (osh->pdev, offset, val);
+      if (offset != PCI_BAR0_WIN)
+       break;
+      if (osl_pci_read_config (osh, offset, size) == val)
+       break;
+    }
+  while (retry--);
+
+#ifdef BCMDBG
+  if (retry < PCI_CFG_RETRY)
+    printk ("PCI CONFIG WRITE access to %d required %d retries\n", offset,
+           (PCI_CFG_RETRY - retry));
+#endif /* BCMDBG */
+}
 
-       ASSERT(osh->magic == OS_HANDLE_MAGIC);
-       kfree(osh);
+/* return bus # for the pci device pointed by osh->pdev */
+uint
+osl_pci_bus (osl_t * osh)
+{
+  ASSERT (osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
+
+  return ((struct pci_dev *) osh->pdev)->bus->number;
 }
 
-/* Return a new packet. zero out pkttag */
-void*
-osl_pktget(osl_t *osh, uint len, bool send)
+/* return slot # for the pci device pointed by osh->pdev */
+uint
+osl_pci_slot (osl_t * osh)
 {
-       struct sk_buff *skb;
+  ASSERT (osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
 
-       if ((skb = dev_alloc_skb(len))) {
-               skb_put(skb, len);
-               skb->priority = 0;
+  return PCI_SLOT (((struct pci_dev *) osh->pdev)->devfn);
+}
 
-#ifdef BCMDBG_PKT
-       pktlist_add(&(osh->pktlist), (void *) skb);
-#endif  /* BCMDBG_PKT */
+static void
+osl_pcmcia_attr (osl_t * osh, uint offset, char *buf, int size, bool write)
+{
+}
 
-               osh->pub.pktalloced++;
-       }
+void
+osl_pcmcia_read_attr (osl_t * osh, uint offset, void *buf, int size)
+{
+  osl_pcmcia_attr (osh, offset, (char *) buf, size, FALSE);
+}
+
+void
+osl_pcmcia_write_attr (osl_t * osh, uint offset, void *buf, int size)
+{
+  osl_pcmcia_attr (osh, offset, (char *) buf, size, TRUE);
+}
+
+
+#ifdef BCMDBG_MEM
+
+void *
+osl_debug_malloc (osl_t * osh, uint size, int line, char *file)
+{
+  bcm_mem_link_t *p;
+  char *basename;
+
+  ASSERT (size);
 
-       return ((void*) skb);
+  if ((p =
+       (bcm_mem_link_t *) osl_malloc (osh,
+                                     sizeof (bcm_mem_link_t) + size)) ==
+      NULL)
+    return (NULL);
+
+  p->size = size;
+  p->line = line;
+
+  basename = strrchr (file, '/');
+  /* skip the '/' */
+  if (basename)
+    basename++;
+
+  if (!basename)
+    basename = file;
+
+  strncpy (p->file, basename, BCM_MEM_FILENAME_LEN);
+  p->file[BCM_MEM_FILENAME_LEN - 1] = '\0';
+
+  /* link this block */
+  p->prev = NULL;
+  p->next = osh->dbgmem_list;
+  if (p->next)
+    p->next->prev = p;
+  osh->dbgmem_list = p;
+
+  return p + 1;
 }
 
-typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, uint16 status);
-/* Free the driver packet. Free the tag if present */
 void
-osl_pktfree(osl_t *osh, void *p, bool send)
+osl_debug_mfree (osl_t * osh, void *addr, uint size, int line, char *file)
 {
-       struct sk_buff *skb, *nskb;
-       pktfree_cb_fn_t tx_fn = osh->pub.tx_fn;
+  bcm_mem_link_t *p =
+    (bcm_mem_link_t *) ((int8 *) addr - sizeof (bcm_mem_link_t));
+
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
+
+  if (p->size == 0)
+    {
+      printk
+       ("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n",
+        addr, size, line, file);
+      ASSERT (p->size);
+      return;
+    }
+
+  if (p->size != size)
+    {
+      printk
+       ("osl_debug_mfree: dealloc size %d does not match alloc size %d on addr %p"
+        " at line %d file %s\n", size, p->size, addr, line, file);
+      ASSERT (p->size == size);
+      return;
+    }
+
+  /* unlink this block */
+  if (p->prev)
+    p->prev->next = p->next;
+  if (p->next)
+    p->next->prev = p->prev;
+  if (osh->dbgmem_list == p)
+    osh->dbgmem_list = p->next;
+  p->next = p->prev = NULL;
+
+  osl_mfree (osh, p, size + sizeof (bcm_mem_link_t));
+}
 
-       skb = (struct sk_buff*) p;
-       
-       if (send && tx_fn)
-               tx_fn(osh->pub.tx_ctx, p, 0);
+int
+osl_debug_memdump (osl_t * osh, struct bcmstrbuf *b)
+{
+  bcm_mem_link_t *p;
 
-       /* perversion: we use skb->next to chain multi-skb packets */
-       while (skb) {
-               nskb = skb->next;
-               skb->next = NULL;
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
 
-#ifdef BCMDBG_PKT
-               pktlist_remove(&(osh->pktlist), (void *) skb);
-#endif  /* BCMDBG_PKT */
+  bcm_bprintf (b, "   Address\tSize\tFile:line\n");
+  for (p = osh->dbgmem_list; p; p = p->next)
+    bcm_bprintf (b, "0x%08x\t%5d\t%s:%d\n",
+                (uintptr) p + sizeof (bcm_mem_link_t), p->size, p->file,
+                p->line);
 
-               if (skb->destructor) {
-                       /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists
-                        */
-                       dev_kfree_skb_any(skb);
-               } else {
-                       /* can free immediately (even in_irq()) if destructor does not exist */
-                       dev_kfree_skb(skb);
-               }
+  return 0;
+}
 
-               osh->pub.pktalloced--;
+#endif /* BCMDBG_MEM */
 
-               skb = nskb;
-       }
+void *
+osl_malloc (osl_t * osh, uint size)
+{
+  void *addr;
+
+  /* only ASSERT if osh is defined */
+  if (osh)
+    ASSERT (osh->magic == OS_HANDLE_MAGIC);
+
+  if ((addr = kmalloc (size, GFP_ATOMIC)) == NULL)
+    {
+      if (osh)
+       osh->failed++;
+      return (NULL);
+    }
+  if (osh)
+    osh->malloced += size;
+
+  return (addr);
 }
 
-void*
-osl_malloc(osl_t *osh, uint size)
+void
+osl_mfree (osl_t * osh, void *addr, uint size)
 {
-       void *addr;
+  if (osh)
+    {
+      ASSERT (osh->magic == OS_HANDLE_MAGIC);
+      osh->malloced -= size;
+    }
+  kfree (addr);
+}
 
-       /* only ASSERT if osh is defined */
-       if (osh)
-               ASSERT(osh->magic == OS_HANDLE_MAGIC);
+uint
+osl_malloced (osl_t * osh)
+{
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
+  return (osh->malloced);
+}
 
-       if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
-               if (osh)
-                       osh->failed++;
-               return (NULL);
-       }
-       if (osh)
-               osh->malloced += size;
+uint
+osl_malloc_failed (osl_t * osh)
+{
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
+  return (osh->failed);
+}
+
+void *
+osl_dma_alloc_consistent (osl_t * osh, uint size, ulong * pap)
+{
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
 
-       return (addr);
+  return (pci_alloc_consistent (osh->pdev, size, (dma_addr_t *) pap));
 }
 
 void
-osl_mfree(osl_t *osh, void *addr, uint size)
+osl_dma_free_consistent (osl_t * osh, void *va, uint size, ulong pa)
 {
-       if (osh) {
-               ASSERT(osh->magic == OS_HANDLE_MAGIC);
-               osh->malloced -= size;
-       }
-       kfree(addr);
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
+
+  pci_free_consistent (osh->pdev, size, va, (dma_addr_t) pa);
 }
 
 uint
-osl_malloced(osl_t *osh)
+osl_dma_map (osl_t * osh, void *va, uint size, int direction)
 {
-       ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
-       return (osh->malloced);
+  int dir;
+
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
+  dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
+  return (pci_map_single (osh->pdev, va, size, dir));
 }
 
-uint osl_malloc_failed(osl_t *osh)
+void
+osl_dma_unmap (osl_t * osh, uint pa, uint size, int direction)
 {
-       ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
-       return (osh->failed);
+  int dir;
+
+  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
+  dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
+  pci_unmap_single (osh->pdev, (uint32) pa, size, dir);
 }
 
-#undef osl_delay
+#if defined(BINOSL) || defined(BCMDBG_ASSERT)
 void
-osl_delay(uint usec)
+osl_assert (char *exp, char *file, int line)
 {
-       OSL_DELAY(usec);
+  char tempbuf[255];
+
+  sprintf (tempbuf, "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
+          file, line);
+  panic (tempbuf);
+}
+#endif /* BCMDBG_ASSERT || BINOSL */
+
+void
+osl_delay (uint usec)
+{
+  uint d;
+
+  while (usec > 0)
+    {
+      d = MIN (usec, 1000);
+      udelay (d);
+      usec -= d;
+    }
 }
 
 /* Clone a packet.
  * The pkttag contents are NOT cloned.
  */
 void *
-osl_pktdup(osl_t *osh, void *skb)
+osl_pktdup (osl_t * osh, void *skb)
+{
+  void *p;
+
+  if ((p = skb_clone ((struct sk_buff *) skb, GFP_ATOMIC)) == NULL)
+    return NULL;
+
+  /* skb_clone copies skb->cb.. we don't want that */
+  if (osh->pub.pkttag)
+    bzero ((void *) ((struct sk_buff *) p)->cb, OSL_PKTTAG_SZ);
+
+  /* Increment the packet counter */
+  osh->pub.pktalloced++;
+#ifdef BCMDBG_PKT
+  pktlist_add (&(osh->pktlist), (void *) p);
+#endif /* BCMDBG_PKT */
+  return (p);
+}
+
+uint
+osl_pktalloced (osl_t * osh)
+{
+  return (osh->pub.pktalloced);
+}
+
+#ifdef BCMDBG_PKT
+char *
+osl_pktlist_dump (osl_t * osh, char *buf)
+{
+  pktlist_dump (&(osh->pktlist), buf);
+  return buf;
+}
+
+void
+osl_pktlist_add (osl_t * osh, void *p)
+{
+  pktlist_add (&(osh->pktlist), p);
+}
+
+void
+osl_pktlist_remove (osl_t * osh, void *p)
+{
+  pktlist_remove (&(osh->pktlist), p);
+}
+#endif /* BCMDBG_PKT */
+
+/*
+ * BINOSL selects the slightly slower function-call-based binary compatible osl.
+ */
+#ifdef BINOSL
+
+int
+osl_printf (const char *format, ...)
+{
+  va_list args;
+  char buf[1024];
+  int len;
+
+  /* sprintf into a local buffer because there *is* no "vprintk()".. */
+  va_start (args, format);
+  len = vsnprintf (buf, 1024, format, args);
+  va_end (args);
+
+  if (len > sizeof (buf))
+    {
+      printk ("osl_printf: buffer overrun\n");
+      return (0);
+    }
+
+  return (printk (buf));
+}
+
+int
+osl_sprintf (char *buf, const char *format, ...)
+{
+  va_list args;
+  int rc;
+
+  va_start (args, format);
+  rc = vsprintf (buf, format, args);
+  va_end (args);
+  return (rc);
+}
+
+int
+osl_strcmp (const char *s1, const char *s2)
+{
+  return (strcmp (s1, s2));
+}
+
+int
+osl_strncmp (const char *s1, const char *s2, uint n)
+{
+  return (strncmp (s1, s2, n));
+}
+
+int
+osl_strlen (const char *s)
+{
+  return (strlen (s));
+}
+
+char *
+osl_strcpy (char *d, const char *s)
+{
+  return (strcpy (d, s));
+}
+
+char *
+osl_strncpy (char *d, const char *s, uint n)
+{
+  return (strncpy (d, s, n));
+}
+
+void
+bcopy (const void *src, void *dst, int len)
+{
+  memcpy (dst, src, len);
+}
+
+int
+bcmp (const void *b1, const void *b2, int len)
+{
+  return (memcmp (b1, b2, len));
+}
+
+void
+bzero (void *b, int len)
+{
+  memset (b, '\0', len);
+}
+
+uint32
+osl_readl (volatile uint32 * r)
+{
+  return (readl (r));
+}
+
+uint16
+osl_readw (volatile uint16 * r)
+{
+  return (readw (r));
+}
+
+uint8
+osl_readb (volatile uint8 * r)
+{
+  return (readb (r));
+}
+
+void
+osl_writel (uint32 v, volatile uint32 * r)
+{
+  writel (v, r);
+}
+
+void
+osl_writew (uint16 v, volatile uint16 * r)
+{
+  writew (v, r);
+}
+
+void
+osl_writeb (uint8 v, volatile uint8 * r)
+{
+  writeb (v, r);
+}
+
+void *
+osl_uncached (void *va)
+{
+#ifdef mips
+  return ((void *) KSEG1ADDR (va));
+#else
+  return ((void *) va);
+#endif /* mips */
+}
+
+uint
+osl_getcycles (void)
 {
-       void * p;
+  uint cycles;
+
+#if defined(mips)
+  cycles = read_c0_count () * 2;
+#elif defined(__i386__)
+  rdtscl (cycles);
+#else
+  cycles = 0;
+#endif /* defined(mips) */
+  return cycles;
+}
 
-       if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL)
-               return NULL;
+void *
+osl_reg_map (uint32 pa, uint size)
+{
+  return (ioremap_nocache ((unsigned long) pa, (unsigned long) size));
+}
 
-       /* skb_clone copies skb->cb.. we don't want that */
-       if (osh->pub.pkttag)
-               bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
+void
+osl_reg_unmap (void *va)
+{
+  iounmap (va);
+}
 
-       /* Increment the packet counter */
-       osh->pub.pktalloced++;
-       return (p);
+int
+osl_busprobe (uint32 * val, uint32 addr)
+{
+#ifdef mips
+  return get_dbe (*val, (uint32 *) addr);
+#else
+  *val = readl ((uint32 *) (uintptr) addr);
+  return 0;
+#endif /* mips */
+}
+
+bool
+osl_pktshared (void *skb)
+{
+  return (((struct sk_buff *) skb)->cloned);
+}
+
+uchar *
+osl_pktdata (osl_t * osh, void *skb)
+{
+  return (((struct sk_buff *) skb)->data);
 }
 
 uint
-osl_pktalloced(osl_t *osh)
+osl_pktlen (osl_t * osh, void *skb)
+{
+  return (((struct sk_buff *) skb)->len);
+}
+
+uint
+osl_pktheadroom (osl_t * osh, void *skb)
+{
+  return (uint) skb_headroom ((struct sk_buff *) skb);
+}
+
+uint
+osl_pkttailroom (osl_t * osh, void *skb)
+{
+  return (uint) skb_tailroom ((struct sk_buff *) skb);
+}
+
+void *
+osl_pktnext (osl_t * osh, void *skb)
+{
+  return (((struct sk_buff *) skb)->next);
+}
+
+void
+osl_pktsetnext (void *skb, void *x)
+{
+  ((struct sk_buff *) skb)->next = (struct sk_buff *) x;
+}
+
+void
+osl_pktsetlen (osl_t * osh, void *skb, uint len)
+{
+  __skb_trim ((struct sk_buff *) skb, len);
+}
+
+uchar *
+osl_pktpush (osl_t * osh, void *skb, int bytes)
+{
+  return (skb_push ((struct sk_buff *) skb, bytes));
+}
+
+uchar *
+osl_pktpull (osl_t * osh, void *skb, int bytes)
+{
+  return (skb_pull ((struct sk_buff *) skb, bytes));
+}
+
+void *
+osl_pkttag (void *skb)
 {
-       return (osh->pub.pktalloced);
+  return ((void *) (((struct sk_buff *) skb)->cb));
+}
+
+void *
+osl_pktlink (void *skb)
+{
+  return (((struct sk_buff *) skb)->prev);
+}
+
+void
+osl_pktsetlink (void *skb, void *x)
+{
+  ((struct sk_buff *) skb)->prev = (struct sk_buff *) x;
+}
+
+uint
+osl_pktprio (void *skb)
+{
+  return (((struct sk_buff *) skb)->priority);
+}
+
+void
+osl_pktsetprio (void *skb, uint x)
+{
+  ((struct sk_buff *) skb)->priority = x;
+}
+
+/* Convert a driver packet to native(OS) packet
+ * In the process, packettag is zeroed out before sending up
+ * IP code depends on skb->cb to be setup correctly with various options
+ * In our case, that means it should be 0
+ */
+struct sk_buff *
+osl_pkt_tonative (osl_t * osh, void *pkt)
+{
+  struct sk_buff *nskb;
+
+  if (osh->pub.pkttag)
+    bzero ((void *) ((struct sk_buff *) pkt)->cb, OSL_PKTTAG_SZ);
+
+  /* Decrement the packet counter */
+  for (nskb = (struct sk_buff *) pkt; nskb; nskb = nskb->next)
+    {
+#ifdef BCMDBG_PKT
+      pktlist_remove (&(osh->pktlist), (void *) nskb);
+#endif /* BCMDBG_PKT */
+      osh->pub.pktalloced--;
+    }
+
+  return (struct sk_buff *) pkt;
+}
+
+/* Convert a native(OS) packet to driver packet.
+ * In the process, native packet is destroyed, there is no copying
+ * Also, a packettag is zeroed out
+ */
+void *
+osl_pkt_frmnative (osl_t * osh, struct sk_buff *skb)
+{
+  struct sk_buff *nskb;
+
+  if (osh->pub.pkttag)
+    bzero ((void *) skb->cb, OSL_PKTTAG_SZ);
+
+  /* Increment the packet counter */
+  for (nskb = skb; nskb; nskb = nskb->next)
+    {
+#ifdef BCMDBG_PKT
+      pktlist_add (&(osh->pktlist), (void *) nskb);
+#endif /* BCMDBG_PKT */
+      osh->pub.pktalloced++;
+    }
+
+  return (void *) skb;
 }
 
+#endif /* BINOSL */