aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/p54/p54usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/p54/p54usb.c')
-rw-r--r--drivers/net/wireless/p54/p54usb.c180
1 files changed, 79 insertions, 101 deletions
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 8a420df605a..7444f372977 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -91,11 +91,16 @@ 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(MAX_RX_SIZE);
+ skb = dev_alloc_skb(priv->common.rx_mtu + 32);
if (unlikely(!skb)) {
usb_free_urb(urb);
/* TODO check rx queue length and refill *somewhere* */
@@ -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)) {
@@ -145,7 +153,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
struct p54u_rx_info *info;
while (skb_queue_len(&priv->rx_queue) < 32) {
- skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL);
+ skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
if (!skb)
break;
entry = usb_alloc_urb(0, GFP_KERNEL);
@@ -153,7 +161,10 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
kfree_skb(skb);
break;
}
- usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb);
+ usb_fill_bulk_urb(entry, priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
+ skb_tail_pointer(skb),
+ priv->common.rx_mtu + 32, p54u_rx_cb, skb);
info = (struct p54u_rx_info *) skb->cb;
info->urb = entry;
info->dev = dev;
@@ -207,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)
{
@@ -312,73 +359,6 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
data, len, &alen, 2000);
}
-static int p54u_read_eeprom(struct ieee80211_hw *dev)
-{
- struct p54u_priv *priv = dev->priv;
- void *buf;
- struct p54_control_hdr *hdr;
- int err, alen;
- size_t offset = priv->hw_type ? 0x10 : 0x20;
-
- buf = kmalloc(0x2020, GFP_KERNEL);
- if (!buf) {
- printk(KERN_ERR "p54usb: cannot allocate memory for "
- "eeprom readback!\n");
- return -ENOMEM;
- }
-
- if (priv->hw_type) {
- *((u32 *) buf) = priv->common.rx_start;
- err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
- if (err) {
- printk(KERN_ERR "p54usb: addr send failed\n");
- goto fail;
- }
- } else {
- struct net2280_reg_write *reg = buf;
- reg->port = cpu_to_le16(NET2280_DEV_U32);
- reg->addr = cpu_to_le32(P54U_DEV_BASE);
- reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
- err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg));
- if (err) {
- printk(KERN_ERR "p54usb: dev_int send failed\n");
- goto fail;
- }
- }
-
- hdr = buf + priv->common.tx_hdr_len;
- p54_fill_eeprom_readback(hdr);
- hdr->req_id = cpu_to_le32(priv->common.rx_start);
- if (priv->common.tx_hdr_len) {
- struct net2280_tx_hdr *tx_hdr = buf;
- tx_hdr->device_addr = hdr->req_id;
- tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN);
- }
-
- /* we can just pretend to send 0x2000 bytes of nothing in the headers */
- err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf,
- EEPROM_READBACK_LEN + priv->common.tx_hdr_len);
- if (err) {
- printk(KERN_ERR "p54usb: eeprom req send failed\n");
- goto fail;
- }
-
- err = usb_bulk_msg(priv->udev,
- usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
- buf, 0x2020, &alen, 1000);
- if (!err && alen > offset) {
- p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset);
- } else {
- printk(KERN_ERR "p54usb: eeprom read failed!\n");
- err = -EINVAL;
- goto fail;
- }
-
- fail:
- kfree(buf);
- return err;
-}
-
static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
{
static char start_string[] = "~~~~<\r";
@@ -412,7 +392,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
goto err_req_fw_failed;
}
- p54_parse_firmware(dev, fw_entry);
+ err = p54_parse_firmware(dev, fw_entry);
+ if (err)
+ goto err_upload_failed;
left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
strcpy(buf, start_string);
@@ -549,7 +531,12 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
return err;
}
- p54_parse_firmware(dev, fw_entry);
+ err = p54_parse_firmware(dev, fw_entry);
+ if (err) {
+ kfree(buf);
+ release_firmware(fw_entry);
+ return err;
+ }
#define P54U_WRITE(type, addr, data) \
do {\
@@ -833,49 +820,40 @@ 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;
- err = p54u_read_eeprom(dev);
+ skb_queue_head_init(&priv->rx_queue);
+
+ p54u_open(dev);
+ err = p54_read_eeprom(dev);
+ p54u_stop(dev);
if (err)
goto err_free_dev;
- if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
- u8 perm_addr[ETH_ALEN];
-
- printk(KERN_WARNING "p54usb: Invalid hwaddr! Using randomly generated MAC addr\n");
- random_ether_addr(perm_addr);
- SET_IEEE80211_PERM_ADDR(dev, perm_addr);
- }
-
- skb_queue_head_init(&priv->rx_queue);
-
err = ieee80211_register_hw(dev);
if (err) {
printk(KERN_ERR "p54usb: Cannot register netdevice\n");
goto err_free_dev;
}
- printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
- wiphy_name(dev->wiphy),
- print_mac(mac, dev->wiphy->perm_addr),
- priv->common.version);
-
return 0;
err_free_dev: