- patches.arch/x86_mce_intel_decode_physical_address.patch:
[linux-flexiantxendom0-3.2.10.git] / drivers / net / wireless / orinoco / main.c
index 413e9ab..ca71f08 100644 (file)
@@ -254,7 +254,7 @@ void set_port_type(struct orinoco_private *priv)
 /* Device methods                                                   */
 /********************************************************************/
 
-static int orinoco_open(struct net_device *dev)
+int orinoco_open(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
@@ -272,8 +272,9 @@ static int orinoco_open(struct net_device *dev)
 
        return err;
 }
+EXPORT_SYMBOL(orinoco_open);
 
-static int orinoco_stop(struct net_device *dev)
+int orinoco_stop(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        int err = 0;
@@ -281,25 +282,27 @@ static int orinoco_stop(struct net_device *dev)
        /* We mustn't use orinoco_lock() here, because we need to be
           able to close the interface even if hw_unavailable is set
           (e.g. as we're released after a PC Card removal) */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
 
        priv->open = 0;
 
        err = __orinoco_down(priv);
 
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        return err;
 }
+EXPORT_SYMBOL(orinoco_stop);
 
-static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
+struct net_device_stats *orinoco_get_stats(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
 
        return &priv->stats;
 }
+EXPORT_SYMBOL(orinoco_get_stats);
 
-static void orinoco_set_multicast_list(struct net_device *dev)
+void orinoco_set_multicast_list(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
@@ -313,8 +316,9 @@ static void orinoco_set_multicast_list(struct net_device *dev)
        __orinoco_set_multicast_list(dev);
        orinoco_unlock(priv, &flags);
 }
+EXPORT_SYMBOL(orinoco_set_multicast_list);
 
-static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
+int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct orinoco_private *priv = ndev_priv(dev);
 
@@ -330,23 +334,115 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 
        return 0;
 }
+EXPORT_SYMBOL(orinoco_change_mtu);
 
 /********************************************************************/
 /* Tx path                                                          */
 /********************************************************************/
 
+/* Add encapsulation and MIC to the existing SKB.
+ * The main xmit routine will then send the whole lot to the card.
+ * Need 8 bytes headroom
+ * Need 8 bytes tailroom
+ *
+ *                          With encapsulated ethernet II frame
+ *                          --------
+ *                          803.3 header (14 bytes)
+ *                           dst[6]
+ * --------                  src[6]
+ * 803.3 header (14 bytes)   len[2]
+ *  dst[6]                  803.2 header (8 bytes)
+ *  src[6]                   encaps[6]
+ *  len[2] <- leave alone -> len[2]
+ * --------                 -------- <-- 0
+ * Payload                  Payload
+ * ...                      ...
+ *
+ * --------                 --------
+ *                          MIC (8 bytes)
+ *                          --------
+ *
+ * returns 0 on success, -ENOMEM on error.
+ */
+int orinoco_process_xmit_skb(struct sk_buff *skb,
+                            struct net_device *dev,
+                            struct orinoco_private *priv,
+                            int *tx_control,
+                            u8 *mic_buf)
+{
+       struct orinoco_tkip_key *key;
+       struct ethhdr *eh;
+       int do_mic;
+
+       key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
+
+       do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
+                 (key != NULL));
+
+       if (do_mic)
+               *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
+                       HERMES_TXCTRL_MIC;
+
+       eh = (struct ethhdr *)skb->data;
+
+       /* Encapsulate Ethernet-II frames */
+       if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
+               struct header_struct {
+                       struct ethhdr eth;      /* 802.3 header */
+                       u8 encap[6];            /* 802.2 header */
+               } __attribute__ ((packed)) hdr;
+               int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
+
+               if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR
+                                      "%s: Not enough headroom for 802.2 headers %d\n",
+                                      dev->name, skb_headroom(skb));
+                       return -ENOMEM;
+               }
+
+               /* Fill in new header */
+               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
+               hdr.eth.h_proto = htons(len);
+               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
+
+               /* Make room for the new header, and copy it in */
+               eh = (struct ethhdr *) skb_push(skb, ENCAPS_OVERHEAD);
+               memcpy(eh, &hdr, sizeof(hdr));
+       }
+
+       /* Calculate Michael MIC */
+       if (do_mic) {
+               size_t len = skb->len - ETH_HLEN;
+               u8 *mic = &mic_buf[0];
+
+               /* Have to write to an even address, so copy the spare
+                * byte across */
+               if (skb->len % 2) {
+                       *mic = skb->data[skb->len - 1];
+                       mic++;
+               }
+
+               orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
+                           eh->h_dest, eh->h_source, 0 /* priority */,
+                           skb->data + ETH_HLEN,
+                           len, mic);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(orinoco_process_xmit_skb);
+
 static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
-       struct orinoco_tkip_key *key;
        hermes_t *hw = &priv->hw;
        int err = 0;
        u16 txfid = priv->txfid;
-       struct ethhdr *eh;
        int tx_control;
        unsigned long flags;
-       int do_mic;
+       u8 mic_buf[MICHAEL_MIC_LEN+1];
 
        if (!netif_running(dev)) {
                printk(KERN_ERR "%s: Tx on stopped device!\n",
@@ -378,16 +474,12 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
        if (skb->len < ETH_HLEN)
                goto drop;
 
-       key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
-
-       do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
-                 (key != NULL));
-
        tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
 
-       if (do_mic)
-               tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
-                       HERMES_TXCTRL_MIC;
+       err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
+                                      &mic_buf[0]);
+       if (err)
+               goto drop;
 
        if (priv->has_alt_txcntl) {
                /* WPA enabled firmwares have tx_cntl at the end of
@@ -400,8 +492,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                memset(&desc, 0, sizeof(desc));
 
                *txcntl = cpu_to_le16(tx_control);
-               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-                                       txfid, 0);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                         txfid, 0);
                if (err) {
                        if (net_ratelimit())
                                printk(KERN_ERR "%s: Error %d writing Tx "
@@ -414,8 +506,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                memset(&desc, 0, sizeof(desc));
 
                desc.tx_control = cpu_to_le16(tx_control);
-               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-                                       txfid, 0);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                         txfid, 0);
                if (err) {
                        if (net_ratelimit())
                                printk(KERN_ERR "%s: Error %d writing Tx "
@@ -430,68 +522,24 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                                   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
        }
 
-       eh = (struct ethhdr *)skb->data;
-
-       /* Encapsulate Ethernet-II frames */
-       if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
-               struct header_struct {
-                       struct ethhdr eth;      /* 802.3 header */
-                       u8 encap[6];            /* 802.2 header */
-               } __attribute__ ((packed)) hdr;
-
-               /* Strip destination and source from the data */
-               skb_pull(skb, 2 * ETH_ALEN);
-
-               /* And move them to a separate header */
-               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
-               hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
-               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
-
-               /* Insert the SNAP header */
-               if (skb_headroom(skb) < sizeof(hdr)) {
-                       printk(KERN_ERR
-                              "%s: Not enough headroom for 802.2 headers %d\n",
-                              dev->name, skb_headroom(skb));
-                       goto drop;
-               }
-               eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
-               memcpy(eh, &hdr, sizeof(hdr));
-       }
-
-       err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
-                               txfid, HERMES_802_3_OFFSET);
+       err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
+                                 txfid, HERMES_802_3_OFFSET);
        if (err) {
                printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
                       dev->name, err);
                goto busy;
        }
 
-       /* Calculate Michael MIC */
-       if (do_mic) {
-               u8 mic_buf[MICHAEL_MIC_LEN + 1];
-               u8 *mic;
-               size_t offset;
-               size_t len;
+       if (tx_control & HERMES_TXCTRL_MIC) {
+               size_t offset = HERMES_802_3_OFFSET + skb->len;
+               size_t len = MICHAEL_MIC_LEN;
 
-               if (skb->len % 2) {
-                       /* MIC start is on an odd boundary */
-                       mic_buf[0] = skb->data[skb->len - 1];
-                       mic = &mic_buf[1];
-                       offset = skb->len - 1;
-                       len = MICHAEL_MIC_LEN + 1;
-               } else {
-                       mic = &mic_buf[0];
-                       offset = skb->len;
-                       len = MICHAEL_MIC_LEN;
+               if (offset % 2) {
+                       offset--;
+                       len++;
                }
-
-               orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
-                           eh->h_dest, eh->h_source, 0 /* priority */,
-                           skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
-
-               /* Write the MIC */
-               err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
-                                       txfid, HERMES_802_3_OFFSET + offset);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
+                                         txfid, offset);
                if (err) {
                        printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
                               dev->name, err);
@@ -502,7 +550,7 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Finally, we actually initiate the send */
        netif_stop_queue(dev);
 
-       err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
+       err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
                                txfid, NULL);
        if (err) {
                netif_start_queue(dev);
@@ -512,7 +560,6 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                goto busy;
        }
 
-       dev->trans_start = jiffies;
        stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
        goto ok;
 
@@ -572,9 +619,9 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
                return; /* Nothing's really happened */
 
        /* Read part of the frame header - we need status and addr1 */
-       err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
-                              sizeof(struct hermes_txexc_data),
-                              fid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr,
+                                sizeof(struct hermes_txexc_data),
+                                fid, 0);
 
        hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
        stats->tx_errors++;
@@ -615,7 +662,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
        netif_wake_queue(dev);
 }
 
-static void orinoco_tx_timeout(struct net_device *dev)
+void orinoco_tx_timeout(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
@@ -630,6 +677,7 @@ static void orinoco_tx_timeout(struct net_device *dev)
 
        schedule_work(&priv->reset_work);
 }
+EXPORT_SYMBOL(orinoco_tx_timeout);
 
 /********************************************************************/
 /* Rx path (data frames)                                            */
@@ -764,9 +812,9 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
 
        /* If any, copy the data from the card to the skb */
        if (datalen > 0) {
-               err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
-                                      ALIGN(datalen, 2), rxfid,
-                                      HERMES_802_2_OFFSET);
+               err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+                                        ALIGN(datalen, 2), rxfid,
+                                        HERMES_802_2_OFFSET);
                if (err) {
                        printk(KERN_ERR "%s: error %d reading monitor frame\n",
                               dev->name, err);
@@ -792,7 +840,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
        stats->rx_dropped++;
 }
 
-static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
+void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
@@ -814,8 +862,8 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 
        rxfid = hermes_read_regn(hw, RXFID);
 
-       err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
-                              rxfid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
+                                rxfid, 0);
        if (err) {
                printk(KERN_ERR "%s: error %d reading Rx descriptor. "
                       "Frame dropped.\n", dev->name, err);
@@ -882,9 +930,9 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
           nothing is removed.  2 is for aligning the IP header.  */
        skb_reserve(skb, ETH_HLEN + 2);
 
-       err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
-                              ALIGN(length, 2), rxfid,
-                              HERMES_802_2_OFFSET);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+                                ALIGN(length, 2), rxfid,
+                                HERMES_802_2_OFFSET);
        if (err) {
                printk(KERN_ERR "%s: error %d reading frame. "
                       "Frame dropped.\n", dev->name, err);
@@ -913,6 +961,7 @@ update_stats:
 out:
        kfree(desc);
 }
+EXPORT_SYMBOL(__orinoco_ev_rx);
 
 static void orinoco_rx(struct net_device *dev,
                       struct hermes_rx_descriptor *desc,
@@ -1145,9 +1194,9 @@ static void orinoco_join_ap(struct work_struct *work)
                goto out;
 
        /* Read scan results from the firmware */
-       err = hermes_read_ltv(hw, USER_BAP,
-                             HERMES_RID_SCANRESULTSTABLE,
-                             MAX_SCAN_LEN, &len, buf);
+       err = hw->ops->read_ltv(hw, USER_BAP,
+                               HERMES_RID_SCANRESULTSTABLE,
+                               MAX_SCAN_LEN, &len, buf);
        if (err) {
                printk(KERN_ERR "%s: Cannot read scan results\n",
                       dev->name);
@@ -1194,8 +1243,8 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
        union iwreq_data wrqu;
        int err;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+                               ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
        if (err != 0)
                return;
 
@@ -1217,8 +1266,8 @@ static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
        if (!priv->has_wpa)
                return;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
-                             sizeof(buf), NULL, &buf);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+                               sizeof(buf), NULL, &buf);
        if (err != 0)
                return;
 
@@ -1247,8 +1296,9 @@ static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
        if (!priv->has_wpa)
                return;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
-                             sizeof(buf), NULL, &buf);
+       err = hw->ops->read_ltv(hw, USER_BAP,
+                               HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+                               sizeof(buf), NULL, &buf);
        if (err != 0)
                return;
 
@@ -1353,7 +1403,7 @@ static void orinoco_process_scan_results(struct work_struct *work)
        spin_unlock_irqrestore(&priv->scan_lock, flags);
 }
 
-static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
+void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        u16 infofid;
@@ -1371,8 +1421,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
        infofid = hermes_read_regn(hw, INFOFID);
 
        /* Read the info frame header - don't try too hard */
-       err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
-                              infofid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info),
+                                infofid, 0);
        if (err) {
                printk(KERN_ERR "%s: error %d reading info frame. "
                       "Frame dropped.\n", dev->name, err);
@@ -1393,8 +1443,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        len = sizeof(tallies);
                }
 
-               err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len,
+                                        infofid, sizeof(info));
                if (err)
                        break;
 
@@ -1429,8 +1479,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
                }
 
-               err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len,
+                                        infofid, sizeof(info));
                if (err)
                        break;
                newstatus = le16_to_cpu(linkstatus.linkstatus);
@@ -1494,8 +1544,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                }
 
                /* Read scan data */
-               err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len,
+                                        infofid, sizeof(info));
                if (err) {
                        kfree(buf);
                        qabort_scan(priv);
@@ -1547,8 +1597,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
 
                /* Read scan data */
-               err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len,
+                                        infofid, sizeof(info));
                if (err)
                        kfree(bss);
                else
@@ -1568,9 +1618,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                /* We don't actually do anything about it */
                break;
        }
-
-       return;
 }
+EXPORT_SYMBOL(__orinoco_ev_info);
 
 static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
 {
@@ -1647,7 +1696,7 @@ static int orinoco_reinit_firmware(struct orinoco_private *priv)
        struct hermes *hw = &priv->hw;
        int err;
 
-       err = hermes_init(hw);
+       err = hw->ops->init(hw);
        if (priv->do_fw_download && !err) {
                err = orinoco_download(priv);
                if (err)
@@ -1735,7 +1784,7 @@ void orinoco_reset(struct work_struct *work)
        }
 
        /* This has to be called from user context */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
 
        priv->hw_unavailable--;
 
@@ -1750,7 +1799,7 @@ void orinoco_reset(struct work_struct *work)
                        dev->trans_start = jiffies;
        }
 
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        return;
  disable:
@@ -1984,7 +2033,7 @@ int orinoco_init(struct orinoco_private *priv)
        priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
 
        /* Initialize the firmware */
-       err = hermes_init(hw);
+       err = hw->ops->init(hw);
        if (err != 0) {
                dev_err(dev, "Failed to initialize firmware (err = %d)\n",
                        err);
@@ -2067,9 +2116,9 @@ int orinoco_init(struct orinoco_private *priv)
 
        /* Make the hardware available, as long as it hasn't been
         * removed elsewhere (e.g. by PCMCIA hot unplug) */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
        priv->hw_unavailable--;
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        dev_dbg(dev, "Ready\n");
 
@@ -2192,7 +2241,8 @@ EXPORT_SYMBOL(alloc_orinocodev);
  */
 int orinoco_if_add(struct orinoco_private *priv,
                   unsigned long base_addr,
-                  unsigned int irq)
+                  unsigned int irq,
+                  const struct net_device_ops *ops)
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct wireless_dev *wdev;
@@ -2211,16 +2261,21 @@ int orinoco_if_add(struct orinoco_private *priv,
 
        /* Setup / override net_device fields */
        dev->ieee80211_ptr = wdev;
-       dev->netdev_ops = &orinoco_netdev_ops;
        dev->watchdog_timeo = HZ; /* 1 second timeout */
        dev->wireless_handlers = &orinoco_handler_def;
 #ifdef WIRELESS_SPY
        dev->wireless_data = &priv->wireless_data;
 #endif
+       /* Default to standard ops if not set */
+       if (ops)
+               dev->netdev_ops = ops;
+       else
+               dev->netdev_ops = &orinoco_netdev_ops;
+
        /* we use the default eth_mac_addr for setting the MAC addr */
 
        /* Reserve space in skb for the SNAP header */
-       dev->hard_header_len += ENCAPS_OVERHEAD;
+       dev->needed_headroom = ENCAPS_OVERHEAD;
 
        netif_carrier_off(dev);
 
@@ -2305,7 +2360,7 @@ int orinoco_up(struct orinoco_private *priv)
        unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
 
        err = orinoco_reinit_firmware(priv);
        if (err) {
@@ -2325,7 +2380,7 @@ int orinoco_up(struct orinoco_private *priv)
        }
 
 exit:
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        return 0;
 }
@@ -2337,7 +2392,7 @@ void orinoco_down(struct orinoco_private *priv)
        unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        err = __orinoco_down(priv);
        if (err)
                printk(KERN_WARNING "%s: Error %d downing interface\n",
@@ -2345,7 +2400,7 @@ void orinoco_down(struct orinoco_private *priv)
 
        netif_device_detach(dev);
        priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 }
 EXPORT_SYMBOL(orinoco_down);