p54usb: support LM87 firmwares
Christian Lamparter [Thu, 4 Sep 2008 10:29:38 +0000 (12:29 +0200)]
This patch adds the necessary changes to support LM87 firmwares.

Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

drivers/net/wireless/p54/p54.h
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/p54/p54common.h
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/p54/p54usb.h

index 3d44ab3..cd2a39f 100644 (file)
@@ -42,6 +42,11 @@ struct p54_control_hdr {
 
 #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
 
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
 struct p54_common {
        u32 rx_start;
        u32 rx_end;
@@ -68,6 +73,7 @@ struct p54_common {
        unsigned int tx_hdr_len;
        void *cached_vdcf;
        unsigned int fw_var;
+       unsigned int fw_interface;
        struct ieee80211_tx_queue_stats tx_stats[8];
        void *eeprom;
        struct completion eeprom_comp;
index 6d8248e..e96bf1a 100644 (file)
@@ -93,7 +93,8 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
                u32 code = le32_to_cpu(bootrec->code);
                switch (code) {
                case BR_CODE_COMPONENT_ID:
-                       switch (be32_to_cpu(*(__be32 *)bootrec->data)) {
+                       priv->fw_interface = be32_to_cpup(bootrec->data);
+                       switch (priv->fw_interface) {
                        case FW_FMAC:
                                printk(KERN_INFO "p54: FreeMAC firmware\n");
                                break;
@@ -104,7 +105,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
                                printk(KERN_INFO "p54: LM86 firmware\n");
                                break;
                        case FW_LM87:
-                               printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n");
+                               printk(KERN_INFO "p54: LM87 firmware\n");
                                break;
                        default:
                                printk(KERN_INFO "p54: unknown firmware\n");
index 5f2af51..c24b5cd 100644 (file)
@@ -50,11 +50,6 @@ struct bootrec_desc {
 #define BR_CODE_END_OF_BRA             0xFF0000FF
 #define LEGACY_BR_CODE_END_OF_BRA      0xFFFFFFFF
 
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
 /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
 
 struct pda_entry {
index eca858c..7444f37 100644 (file)
@@ -91,8 +91,13 @@ static void p54u_rx_cb(struct urb *urb)
 
        skb_unlink(skb, &priv->rx_queue);
        skb_put(skb, urb->actual_length);
-       if (!priv->hw_type)
-               skb_pull(skb, sizeof(struct net2280_tx_hdr));
+
+       if (priv->hw_type == P54U_NET2280)
+               skb_pull(skb, priv->common.tx_hdr_len);
+       if (priv->common.fw_interface == FW_LM87) {
+               skb_pull(skb, 4);
+               skb_put(skb, 4);
+       }
 
        if (p54_rx(dev, skb)) {
                skb = dev_alloc_skb(priv->common.rx_mtu + 32);
@@ -109,9 +114,12 @@ static void p54u_rx_cb(struct urb *urb)
                urb->context = skb;
                skb_queue_tail(&priv->rx_queue, skb);
        } else {
-               if (!priv->hw_type)
-                       skb_push(skb, sizeof(struct net2280_tx_hdr));
-
+               if (priv->hw_type == P54U_NET2280)
+                       skb_push(skb, priv->common.tx_hdr_len);
+               if (priv->common.fw_interface == FW_LM87) {
+                       skb_push(skb, 4);
+                       skb_put(skb, 4);
+               }
                skb_reset_tail_pointer(skb);
                skb_trim(skb, 0);
                if (urb->transfer_buffer != skb_tail_pointer(skb)) {
@@ -210,6 +218,42 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
        usb_submit_urb(data_urb, GFP_ATOMIC);
 }
 
+__le32 p54u_lm87_chksum(const u32 *data, size_t length)
+{
+       __le32 chk = 0;
+
+       length >>= 2;
+       while (length--) {
+               chk ^= cpu_to_le32(*data++);
+               chk = (chk >> 5) ^ (chk << 3);
+       }
+
+       return chk;
+}
+
+static void p54u_tx_lm87(struct ieee80211_hw *dev,
+                        struct p54_control_hdr *data,
+                        size_t len, int free_on_tx)
+{
+       struct p54u_priv *priv = dev->priv;
+       struct urb *data_urb;
+       struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr);
+
+       data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!data_urb)
+               return;
+
+       hdr->chksum = p54u_lm87_chksum((u32 *)data, len);
+       hdr->device_addr = data->req_id;
+
+       usb_fill_bulk_urb(data_urb, priv->udev,
+               usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr,
+               len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb,
+               dev);
+
+       usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
 static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
                            size_t len, int free_on_tx)
 {
@@ -776,21 +820,23 @@ static int __devinit p54u_probe(struct usb_interface *intf,
                }
        }
        priv->common.open = p54u_open;
-
+       priv->common.stop = p54u_stop;
        if (recognized_pipes < P54U_PIPE_NUMBER) {
                priv->hw_type = P54U_3887;
-               priv->common.tx = p54u_tx_3887;
+               err = p54u_upload_firmware_3887(dev);
+               if (priv->common.fw_interface == FW_LM87) {
+                       dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
+                       priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
+                       priv->common.tx = p54u_tx_lm87;
+               } else
+                       priv->common.tx = p54u_tx_3887;
        } else {
+               priv->hw_type = P54U_NET2280;
                dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
                priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
                priv->common.tx = p54u_tx_net2280;
-       }
-       priv->common.stop = p54u_stop;
-
-       if (priv->hw_type)
-               err = p54u_upload_firmware_3887(dev);
-       else
                err = p54u_upload_firmware_net2280(dev);
+       }
        if (err)
                goto err_free_dev;
 
index 1baaff0..5b8fe91 100644 (file)
@@ -72,6 +72,11 @@ struct net2280_tx_hdr {
        u8 padding[8];
 } __attribute__((packed));
 
+struct lm87_tx_hdr {
+       __le32 device_addr;
+       __le32 chksum;
+} __attribute__((packed));
+
 /* Some flags for the isl hardware registers controlling DMA inside the
  * chip */
 #define ISL38XX_DMA_STATUS_DONE                        0x00000001