diff options
Diffstat (limited to 'drivers/net/wireless/p54/p54usb.c')
-rw-r--r-- | drivers/net/wireless/p54/p54usb.c | 203 |
1 files changed, 91 insertions, 112 deletions
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index cbaca23a945..75d749bccb0 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -39,6 +39,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */ {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ + {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ @@ -63,8 +64,8 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */ {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ - {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */ + {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */ {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */ {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ @@ -91,11 +92,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 +115,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 +154,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 +162,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 +219,42 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, usb_submit_urb(data_urb, GFP_ATOMIC); } +static __le32 p54u_lm87_chksum(const u32 *data, size_t length) +{ + u32 chk = 0; + + length >>= 2; + while (length--) { + chk ^= *data++; + chk = (chk >> 5) ^ (chk << 3); + } + + return cpu_to_le32(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 +360,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 "prism54usb: 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 "prism54usb: 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 "prism54usb: 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 "prism54usb: 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 "prism54usb: 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 +393,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); @@ -458,7 +441,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); if (err) { - printk(KERN_ERR "prism54usb: firmware upload failed!\n"); + printk(KERN_ERR "p54usb: firmware upload failed!\n"); goto err_upload_failed; } @@ -469,7 +452,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { - printk(KERN_ERR "prism54usb: firmware upload failed!\n"); + printk(KERN_ERR "p54usb: firmware upload failed!\n"); goto err_upload_failed; } @@ -480,13 +463,13 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) break; if (alen > 5 && !memcmp(buf, "ERROR", 5)) { - printk(KERN_INFO "prism54usb: firmware upload failed!\n"); + printk(KERN_INFO "p54usb: firmware upload failed!\n"); err = -EINVAL; break; } if (time_after(jiffies, timeout)) { - printk(KERN_ERR "prism54usb: firmware boot timed out!\n"); + printk(KERN_ERR "p54usb: firmware boot timed out!\n"); err = -ETIMEDOUT; break; } @@ -498,7 +481,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) buf[1] = '\r'; err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); if (err) { - printk(KERN_ERR "prism54usb: firmware boot failed!\n"); + printk(KERN_ERR "p54usb: firmware boot failed!\n"); goto err_upload_failed; } @@ -549,7 +532,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 {\ @@ -660,7 +648,7 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); if (err) { - printk(KERN_ERR "prism54usb: firmware block upload " + printk(KERN_ERR "p54usb: firmware block upload " "failed\n"); goto fail; } @@ -694,7 +682,7 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) 0x002C | (unsigned long)&devreg->direct_mem_win); if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { - printk(KERN_ERR "prism54usb: firmware DMA transfer " + printk(KERN_ERR "p54usb: firmware DMA transfer " "failed\n"); goto fail; } @@ -802,7 +790,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, dev = p54_init_common(sizeof(*priv)); if (!dev) { - printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n"); + printk(KERN_ERR "p54usb: ieee80211 alloc failed\n"); return -ENOMEM; } @@ -833,49 +821,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 "prism54usb: 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 "prism54usb: Cannot register netdevice\n"); + 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: @@ -902,7 +881,7 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) } static struct usb_driver p54u_driver = { - .name = "prism54usb", + .name = "p54usb", .id_table = p54u_table, .probe = p54u_probe, .disconnect = p54u_disconnect, |