168d57a07SSrinivasan Raju // SPDX-License-Identifier: GPL-2.0-only
268d57a07SSrinivasan Raju /*
368d57a07SSrinivasan Raju * Copyright (c) 2021 pureLiFi
468d57a07SSrinivasan Raju */
568d57a07SSrinivasan Raju
668d57a07SSrinivasan Raju #include <linux/kernel.h>
768d57a07SSrinivasan Raju #include <linux/init.h>
868d57a07SSrinivasan Raju #include <linux/device.h>
968d57a07SSrinivasan Raju #include <linux/errno.h>
1068d57a07SSrinivasan Raju #include <linux/slab.h>
1168d57a07SSrinivasan Raju #include <linux/skbuff.h>
1268d57a07SSrinivasan Raju #include <linux/usb.h>
1368d57a07SSrinivasan Raju #include <linux/workqueue.h>
1468d57a07SSrinivasan Raju #include <linux/proc_fs.h>
1568d57a07SSrinivasan Raju #include <linux/fs.h>
1668d57a07SSrinivasan Raju #include <linux/string.h>
1768d57a07SSrinivasan Raju #include <linux/module.h>
1868d57a07SSrinivasan Raju #include <net/mac80211.h>
1968d57a07SSrinivasan Raju #include <asm/unaligned.h>
2068d57a07SSrinivasan Raju #include <linux/sysfs.h>
2168d57a07SSrinivasan Raju
2268d57a07SSrinivasan Raju #include "mac.h"
2368d57a07SSrinivasan Raju #include "usb.h"
2468d57a07SSrinivasan Raju #include "chip.h"
2568d57a07SSrinivasan Raju
2668d57a07SSrinivasan Raju static const struct usb_device_id usb_ids[] = {
2768d57a07SSrinivasan Raju { USB_DEVICE(PURELIFI_X_VENDOR_ID_0, PURELIFI_X_PRODUCT_ID_0),
2868d57a07SSrinivasan Raju .driver_info = DEVICE_LIFI_X },
2968d57a07SSrinivasan Raju { USB_DEVICE(PURELIFI_XC_VENDOR_ID_0, PURELIFI_XC_PRODUCT_ID_0),
3068d57a07SSrinivasan Raju .driver_info = DEVICE_LIFI_XC },
3168d57a07SSrinivasan Raju { USB_DEVICE(PURELIFI_XL_VENDOR_ID_0, PURELIFI_XL_PRODUCT_ID_0),
3268d57a07SSrinivasan Raju .driver_info = DEVICE_LIFI_XL },
3368d57a07SSrinivasan Raju {}
3468d57a07SSrinivasan Raju };
3568d57a07SSrinivasan Raju
plfxlc_send_packet_from_data_queue(struct plfxlc_usb * usb)3668d57a07SSrinivasan Raju void plfxlc_send_packet_from_data_queue(struct plfxlc_usb *usb)
3768d57a07SSrinivasan Raju {
3868d57a07SSrinivasan Raju struct plfxlc_usb_tx *tx = &usb->tx;
3968d57a07SSrinivasan Raju struct sk_buff *skb = NULL;
4068d57a07SSrinivasan Raju unsigned long flags;
4168d57a07SSrinivasan Raju u8 last_served_sidx;
4268d57a07SSrinivasan Raju
4368d57a07SSrinivasan Raju spin_lock_irqsave(&tx->lock, flags);
4468d57a07SSrinivasan Raju last_served_sidx = usb->sidx;
4568d57a07SSrinivasan Raju do {
4668d57a07SSrinivasan Raju usb->sidx = (usb->sidx + 1) % MAX_STA_NUM;
4768d57a07SSrinivasan Raju if (!(tx->station[usb->sidx].flag & STATION_CONNECTED_FLAG))
4868d57a07SSrinivasan Raju continue;
4968d57a07SSrinivasan Raju if (!(tx->station[usb->sidx].flag & STATION_FIFO_FULL_FLAG))
5068d57a07SSrinivasan Raju skb = skb_peek(&tx->station[usb->sidx].data_list);
5168d57a07SSrinivasan Raju } while ((usb->sidx != last_served_sidx) && (!skb));
5268d57a07SSrinivasan Raju
5368d57a07SSrinivasan Raju if (skb) {
5468d57a07SSrinivasan Raju skb = skb_dequeue(&tx->station[usb->sidx].data_list);
5568d57a07SSrinivasan Raju plfxlc_usb_wreq_async(usb, skb->data, skb->len, USB_REQ_DATA_TX,
5668d57a07SSrinivasan Raju plfxlc_tx_urb_complete, skb);
5768d57a07SSrinivasan Raju if (skb_queue_len(&tx->station[usb->sidx].data_list) <= 60)
5868d57a07SSrinivasan Raju ieee80211_wake_queues(plfxlc_usb_to_hw(usb));
5968d57a07SSrinivasan Raju }
6068d57a07SSrinivasan Raju spin_unlock_irqrestore(&tx->lock, flags);
6168d57a07SSrinivasan Raju }
6268d57a07SSrinivasan Raju
handle_rx_packet(struct plfxlc_usb * usb,const u8 * buffer,unsigned int length)6368d57a07SSrinivasan Raju static void handle_rx_packet(struct plfxlc_usb *usb, const u8 *buffer,
6468d57a07SSrinivasan Raju unsigned int length)
6568d57a07SSrinivasan Raju {
6668d57a07SSrinivasan Raju plfxlc_mac_rx(plfxlc_usb_to_hw(usb), buffer, length);
6768d57a07SSrinivasan Raju }
6868d57a07SSrinivasan Raju
rx_urb_complete(struct urb * urb)6968d57a07SSrinivasan Raju static void rx_urb_complete(struct urb *urb)
7068d57a07SSrinivasan Raju {
7168d57a07SSrinivasan Raju struct plfxlc_usb_tx *tx;
7268d57a07SSrinivasan Raju struct plfxlc_usb *usb;
7368d57a07SSrinivasan Raju unsigned int length;
7468d57a07SSrinivasan Raju const u8 *buffer;
7568d57a07SSrinivasan Raju u16 status;
7668d57a07SSrinivasan Raju u8 sidx;
7768d57a07SSrinivasan Raju int r;
7868d57a07SSrinivasan Raju
7968d57a07SSrinivasan Raju if (!urb) {
8068d57a07SSrinivasan Raju pr_err("urb is NULL\n");
8168d57a07SSrinivasan Raju return;
8268d57a07SSrinivasan Raju }
8368d57a07SSrinivasan Raju if (!urb->context) {
8468d57a07SSrinivasan Raju pr_err("urb ctx is NULL\n");
8568d57a07SSrinivasan Raju return;
8668d57a07SSrinivasan Raju }
8768d57a07SSrinivasan Raju usb = urb->context;
8868d57a07SSrinivasan Raju
8968d57a07SSrinivasan Raju if (usb->initialized != 1) {
9068d57a07SSrinivasan Raju pr_err("usb is not initialized\n");
9168d57a07SSrinivasan Raju return;
9268d57a07SSrinivasan Raju }
9368d57a07SSrinivasan Raju
9468d57a07SSrinivasan Raju tx = &usb->tx;
9568d57a07SSrinivasan Raju switch (urb->status) {
9668d57a07SSrinivasan Raju case 0:
9768d57a07SSrinivasan Raju break;
9868d57a07SSrinivasan Raju case -ESHUTDOWN:
9968d57a07SSrinivasan Raju case -EINVAL:
10068d57a07SSrinivasan Raju case -ENODEV:
10168d57a07SSrinivasan Raju case -ENOENT:
10268d57a07SSrinivasan Raju case -ECONNRESET:
10368d57a07SSrinivasan Raju case -EPIPE:
10468d57a07SSrinivasan Raju dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status);
10568d57a07SSrinivasan Raju return;
10668d57a07SSrinivasan Raju default:
10768d57a07SSrinivasan Raju dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status);
10868d57a07SSrinivasan Raju if (tx->submitted_urbs++ < PURELIFI_URB_RETRY_MAX) {
10968d57a07SSrinivasan Raju dev_dbg(plfxlc_urb_dev(urb), "urb %p resubmit %d", urb,
11068d57a07SSrinivasan Raju tx->submitted_urbs++);
11168d57a07SSrinivasan Raju goto resubmit;
11268d57a07SSrinivasan Raju } else {
11368d57a07SSrinivasan Raju dev_dbg(plfxlc_urb_dev(urb), "urb %p max resubmits reached", urb);
11468d57a07SSrinivasan Raju tx->submitted_urbs = 0;
11568d57a07SSrinivasan Raju return;
11668d57a07SSrinivasan Raju }
11768d57a07SSrinivasan Raju }
11868d57a07SSrinivasan Raju
11968d57a07SSrinivasan Raju buffer = urb->transfer_buffer;
12068d57a07SSrinivasan Raju length = le32_to_cpu(*(__le32 *)(buffer + sizeof(struct rx_status)))
12168d57a07SSrinivasan Raju + sizeof(u32);
12268d57a07SSrinivasan Raju
12368d57a07SSrinivasan Raju if (urb->actual_length != (PLF_MSG_STATUS_OFFSET + 1)) {
12468d57a07SSrinivasan Raju if (usb->initialized && usb->link_up)
12568d57a07SSrinivasan Raju handle_rx_packet(usb, buffer, length);
12668d57a07SSrinivasan Raju goto resubmit;
12768d57a07SSrinivasan Raju }
12868d57a07SSrinivasan Raju
12968d57a07SSrinivasan Raju status = buffer[PLF_MSG_STATUS_OFFSET];
13068d57a07SSrinivasan Raju
13168d57a07SSrinivasan Raju switch (status) {
13268d57a07SSrinivasan Raju case STATION_FIFO_ALMOST_FULL_NOT_MESSAGE:
13368d57a07SSrinivasan Raju dev_dbg(&usb->intf->dev,
13468d57a07SSrinivasan Raju "FIFO full not packet receipt\n");
13568d57a07SSrinivasan Raju tx->mac_fifo_full = 1;
13668d57a07SSrinivasan Raju for (sidx = 0; sidx < MAX_STA_NUM; sidx++)
13768d57a07SSrinivasan Raju tx->station[sidx].flag |= STATION_FIFO_FULL_FLAG;
13868d57a07SSrinivasan Raju break;
13968d57a07SSrinivasan Raju case STATION_FIFO_ALMOST_FULL_MESSAGE:
14068d57a07SSrinivasan Raju dev_dbg(&usb->intf->dev, "FIFO full packet receipt\n");
14168d57a07SSrinivasan Raju
14268d57a07SSrinivasan Raju for (sidx = 0; sidx < MAX_STA_NUM; sidx++)
14368d57a07SSrinivasan Raju tx->station[sidx].flag &= STATION_ACTIVE_FLAG;
14468d57a07SSrinivasan Raju
14568d57a07SSrinivasan Raju plfxlc_send_packet_from_data_queue(usb);
14668d57a07SSrinivasan Raju break;
14768d57a07SSrinivasan Raju case STATION_CONNECT_MESSAGE:
14868d57a07SSrinivasan Raju usb->link_up = 1;
14968d57a07SSrinivasan Raju dev_dbg(&usb->intf->dev, "ST_CONNECT_MSG packet receipt\n");
15068d57a07SSrinivasan Raju break;
15168d57a07SSrinivasan Raju case STATION_DISCONNECT_MESSAGE:
15268d57a07SSrinivasan Raju usb->link_up = 0;
15368d57a07SSrinivasan Raju dev_dbg(&usb->intf->dev, "ST_DISCONN_MSG packet receipt\n");
15468d57a07SSrinivasan Raju break;
15568d57a07SSrinivasan Raju default:
15668d57a07SSrinivasan Raju dev_dbg(&usb->intf->dev, "Unknown packet receipt\n");
15768d57a07SSrinivasan Raju break;
15868d57a07SSrinivasan Raju }
15968d57a07SSrinivasan Raju
16068d57a07SSrinivasan Raju resubmit:
16168d57a07SSrinivasan Raju r = usb_submit_urb(urb, GFP_ATOMIC);
16268d57a07SSrinivasan Raju if (r)
16368d57a07SSrinivasan Raju dev_dbg(plfxlc_urb_dev(urb), "urb %p resubmit fail (%d)\n", urb, r);
16468d57a07SSrinivasan Raju }
16568d57a07SSrinivasan Raju
alloc_rx_urb(struct plfxlc_usb * usb)16668d57a07SSrinivasan Raju static struct urb *alloc_rx_urb(struct plfxlc_usb *usb)
16768d57a07SSrinivasan Raju {
16868d57a07SSrinivasan Raju struct usb_device *udev = plfxlc_usb_to_usbdev(usb);
16968d57a07SSrinivasan Raju struct urb *urb;
17068d57a07SSrinivasan Raju void *buffer;
17168d57a07SSrinivasan Raju
17268d57a07SSrinivasan Raju urb = usb_alloc_urb(0, GFP_KERNEL);
17368d57a07SSrinivasan Raju if (!urb)
17468d57a07SSrinivasan Raju return NULL;
17568d57a07SSrinivasan Raju
17668d57a07SSrinivasan Raju buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
17768d57a07SSrinivasan Raju &urb->transfer_dma);
17868d57a07SSrinivasan Raju if (!buffer) {
17968d57a07SSrinivasan Raju usb_free_urb(urb);
18068d57a07SSrinivasan Raju return NULL;
18168d57a07SSrinivasan Raju }
18268d57a07SSrinivasan Raju
18368d57a07SSrinivasan Raju usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
18468d57a07SSrinivasan Raju buffer, USB_MAX_RX_SIZE,
18568d57a07SSrinivasan Raju rx_urb_complete, usb);
18668d57a07SSrinivasan Raju urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
18768d57a07SSrinivasan Raju
18868d57a07SSrinivasan Raju return urb;
18968d57a07SSrinivasan Raju }
19068d57a07SSrinivasan Raju
free_rx_urb(struct urb * urb)19168d57a07SSrinivasan Raju static void free_rx_urb(struct urb *urb)
19268d57a07SSrinivasan Raju {
19368d57a07SSrinivasan Raju if (!urb)
19468d57a07SSrinivasan Raju return;
19568d57a07SSrinivasan Raju usb_free_coherent(urb->dev, urb->transfer_buffer_length,
19668d57a07SSrinivasan Raju urb->transfer_buffer, urb->transfer_dma);
19768d57a07SSrinivasan Raju usb_free_urb(urb);
19868d57a07SSrinivasan Raju }
19968d57a07SSrinivasan Raju
__lf_x_usb_enable_rx(struct plfxlc_usb * usb)20068d57a07SSrinivasan Raju static int __lf_x_usb_enable_rx(struct plfxlc_usb *usb)
20168d57a07SSrinivasan Raju {
20268d57a07SSrinivasan Raju struct plfxlc_usb_rx *rx = &usb->rx;
20368d57a07SSrinivasan Raju struct urb **urbs;
20468d57a07SSrinivasan Raju int i, r;
20568d57a07SSrinivasan Raju
20668d57a07SSrinivasan Raju r = -ENOMEM;
20768d57a07SSrinivasan Raju urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
20868d57a07SSrinivasan Raju if (!urbs)
20968d57a07SSrinivasan Raju goto error;
21068d57a07SSrinivasan Raju
21168d57a07SSrinivasan Raju for (i = 0; i < RX_URBS_COUNT; i++) {
21268d57a07SSrinivasan Raju urbs[i] = alloc_rx_urb(usb);
21368d57a07SSrinivasan Raju if (!urbs[i])
21468d57a07SSrinivasan Raju goto error;
21568d57a07SSrinivasan Raju }
21668d57a07SSrinivasan Raju
21768d57a07SSrinivasan Raju spin_lock_irq(&rx->lock);
21868d57a07SSrinivasan Raju
21968d57a07SSrinivasan Raju dev_dbg(plfxlc_usb_dev(usb), "irq_disabled %d\n", irqs_disabled());
22068d57a07SSrinivasan Raju
22168d57a07SSrinivasan Raju if (rx->urbs) {
22268d57a07SSrinivasan Raju spin_unlock_irq(&rx->lock);
22368d57a07SSrinivasan Raju r = 0;
22468d57a07SSrinivasan Raju goto error;
22568d57a07SSrinivasan Raju }
22668d57a07SSrinivasan Raju rx->urbs = urbs;
22768d57a07SSrinivasan Raju rx->urbs_count = RX_URBS_COUNT;
22868d57a07SSrinivasan Raju spin_unlock_irq(&rx->lock);
22968d57a07SSrinivasan Raju
23068d57a07SSrinivasan Raju for (i = 0; i < RX_URBS_COUNT; i++) {
23168d57a07SSrinivasan Raju r = usb_submit_urb(urbs[i], GFP_KERNEL);
23268d57a07SSrinivasan Raju if (r)
23368d57a07SSrinivasan Raju goto error_submit;
23468d57a07SSrinivasan Raju }
23568d57a07SSrinivasan Raju
23668d57a07SSrinivasan Raju return 0;
23768d57a07SSrinivasan Raju
23868d57a07SSrinivasan Raju error_submit:
23968d57a07SSrinivasan Raju for (i = 0; i < RX_URBS_COUNT; i++)
24068d57a07SSrinivasan Raju usb_kill_urb(urbs[i]);
24168d57a07SSrinivasan Raju spin_lock_irq(&rx->lock);
24268d57a07SSrinivasan Raju rx->urbs = NULL;
24368d57a07SSrinivasan Raju rx->urbs_count = 0;
24468d57a07SSrinivasan Raju spin_unlock_irq(&rx->lock);
24568d57a07SSrinivasan Raju error:
24668d57a07SSrinivasan Raju if (urbs) {
24768d57a07SSrinivasan Raju for (i = 0; i < RX_URBS_COUNT; i++)
24868d57a07SSrinivasan Raju free_rx_urb(urbs[i]);
24968d57a07SSrinivasan Raju }
250895b3b06SZiyang Xuan kfree(urbs);
25168d57a07SSrinivasan Raju return r;
25268d57a07SSrinivasan Raju }
25368d57a07SSrinivasan Raju
plfxlc_usb_enable_rx(struct plfxlc_usb * usb)25468d57a07SSrinivasan Raju int plfxlc_usb_enable_rx(struct plfxlc_usb *usb)
25568d57a07SSrinivasan Raju {
25668d57a07SSrinivasan Raju struct plfxlc_usb_rx *rx = &usb->rx;
25768d57a07SSrinivasan Raju int r;
25868d57a07SSrinivasan Raju
25968d57a07SSrinivasan Raju mutex_lock(&rx->setup_mutex);
26068d57a07SSrinivasan Raju r = __lf_x_usb_enable_rx(usb);
26168d57a07SSrinivasan Raju if (!r)
26268d57a07SSrinivasan Raju usb->rx_usb_enabled = 1;
26368d57a07SSrinivasan Raju
26468d57a07SSrinivasan Raju mutex_unlock(&rx->setup_mutex);
26568d57a07SSrinivasan Raju
26668d57a07SSrinivasan Raju return r;
26768d57a07SSrinivasan Raju }
26868d57a07SSrinivasan Raju
__lf_x_usb_disable_rx(struct plfxlc_usb * usb)26968d57a07SSrinivasan Raju static void __lf_x_usb_disable_rx(struct plfxlc_usb *usb)
27068d57a07SSrinivasan Raju {
27168d57a07SSrinivasan Raju struct plfxlc_usb_rx *rx = &usb->rx;
27268d57a07SSrinivasan Raju unsigned long flags;
27368d57a07SSrinivasan Raju unsigned int count;
27468d57a07SSrinivasan Raju struct urb **urbs;
27568d57a07SSrinivasan Raju int i;
27668d57a07SSrinivasan Raju
27768d57a07SSrinivasan Raju spin_lock_irqsave(&rx->lock, flags);
27868d57a07SSrinivasan Raju urbs = rx->urbs;
27968d57a07SSrinivasan Raju count = rx->urbs_count;
28068d57a07SSrinivasan Raju spin_unlock_irqrestore(&rx->lock, flags);
28168d57a07SSrinivasan Raju
28268d57a07SSrinivasan Raju if (!urbs)
28368d57a07SSrinivasan Raju return;
28468d57a07SSrinivasan Raju
28568d57a07SSrinivasan Raju for (i = 0; i < count; i++) {
28668d57a07SSrinivasan Raju usb_kill_urb(urbs[i]);
28768d57a07SSrinivasan Raju free_rx_urb(urbs[i]);
28868d57a07SSrinivasan Raju }
28968d57a07SSrinivasan Raju kfree(urbs);
29068d57a07SSrinivasan Raju rx->urbs = NULL;
29168d57a07SSrinivasan Raju rx->urbs_count = 0;
29268d57a07SSrinivasan Raju }
29368d57a07SSrinivasan Raju
plfxlc_usb_disable_rx(struct plfxlc_usb * usb)29468d57a07SSrinivasan Raju void plfxlc_usb_disable_rx(struct plfxlc_usb *usb)
29568d57a07SSrinivasan Raju {
29668d57a07SSrinivasan Raju struct plfxlc_usb_rx *rx = &usb->rx;
29768d57a07SSrinivasan Raju
29868d57a07SSrinivasan Raju mutex_lock(&rx->setup_mutex);
29968d57a07SSrinivasan Raju __lf_x_usb_disable_rx(usb);
30068d57a07SSrinivasan Raju usb->rx_usb_enabled = 0;
30168d57a07SSrinivasan Raju mutex_unlock(&rx->setup_mutex);
30268d57a07SSrinivasan Raju }
30368d57a07SSrinivasan Raju
plfxlc_usb_disable_tx(struct plfxlc_usb * usb)30468d57a07SSrinivasan Raju void plfxlc_usb_disable_tx(struct plfxlc_usb *usb)
30568d57a07SSrinivasan Raju {
30668d57a07SSrinivasan Raju struct plfxlc_usb_tx *tx = &usb->tx;
30768d57a07SSrinivasan Raju unsigned long flags;
30868d57a07SSrinivasan Raju
30968d57a07SSrinivasan Raju clear_bit(PLF_BIT_ENABLED, &tx->enabled);
31068d57a07SSrinivasan Raju
31168d57a07SSrinivasan Raju /* kill all submitted tx-urbs */
31268d57a07SSrinivasan Raju usb_kill_anchored_urbs(&tx->submitted);
31368d57a07SSrinivasan Raju
31468d57a07SSrinivasan Raju spin_lock_irqsave(&tx->lock, flags);
31568d57a07SSrinivasan Raju WARN_ON(!skb_queue_empty(&tx->submitted_skbs));
31668d57a07SSrinivasan Raju WARN_ON(tx->submitted_urbs != 0);
31768d57a07SSrinivasan Raju tx->submitted_urbs = 0;
31868d57a07SSrinivasan Raju spin_unlock_irqrestore(&tx->lock, flags);
31968d57a07SSrinivasan Raju
32068d57a07SSrinivasan Raju /* The stopped state is ignored, relying on ieee80211_wake_queues()
32168d57a07SSrinivasan Raju * in a potentionally following plfxlc_usb_enable_tx().
32268d57a07SSrinivasan Raju */
32368d57a07SSrinivasan Raju }
32468d57a07SSrinivasan Raju
plfxlc_usb_enable_tx(struct plfxlc_usb * usb)32568d57a07SSrinivasan Raju void plfxlc_usb_enable_tx(struct plfxlc_usb *usb)
32668d57a07SSrinivasan Raju {
32768d57a07SSrinivasan Raju struct plfxlc_usb_tx *tx = &usb->tx;
32868d57a07SSrinivasan Raju unsigned long flags;
32968d57a07SSrinivasan Raju
33068d57a07SSrinivasan Raju spin_lock_irqsave(&tx->lock, flags);
33168d57a07SSrinivasan Raju set_bit(PLF_BIT_ENABLED, &tx->enabled);
33268d57a07SSrinivasan Raju tx->submitted_urbs = 0;
33368d57a07SSrinivasan Raju ieee80211_wake_queues(plfxlc_usb_to_hw(usb));
33468d57a07SSrinivasan Raju tx->stopped = 0;
33568d57a07SSrinivasan Raju spin_unlock_irqrestore(&tx->lock, flags);
33668d57a07SSrinivasan Raju }
33768d57a07SSrinivasan Raju
plfxlc_tx_urb_complete(struct urb * urb)33868d57a07SSrinivasan Raju void plfxlc_tx_urb_complete(struct urb *urb)
33968d57a07SSrinivasan Raju {
34068d57a07SSrinivasan Raju struct ieee80211_tx_info *info;
34168d57a07SSrinivasan Raju struct plfxlc_usb *usb;
34268d57a07SSrinivasan Raju struct sk_buff *skb;
34368d57a07SSrinivasan Raju
34468d57a07SSrinivasan Raju skb = urb->context;
34568d57a07SSrinivasan Raju info = IEEE80211_SKB_CB(skb);
34668d57a07SSrinivasan Raju /* grab 'usb' pointer before handing off the skb (since
34768d57a07SSrinivasan Raju * it might be freed by plfxlc_mac_tx_to_dev or mac80211)
34868d57a07SSrinivasan Raju */
34968d57a07SSrinivasan Raju usb = &plfxlc_hw_mac(info->rate_driver_data[0])->chip.usb;
35068d57a07SSrinivasan Raju
35168d57a07SSrinivasan Raju switch (urb->status) {
35268d57a07SSrinivasan Raju case 0:
35368d57a07SSrinivasan Raju break;
35468d57a07SSrinivasan Raju case -ESHUTDOWN:
35568d57a07SSrinivasan Raju case -EINVAL:
35668d57a07SSrinivasan Raju case -ENODEV:
35768d57a07SSrinivasan Raju case -ENOENT:
35868d57a07SSrinivasan Raju case -ECONNRESET:
35968d57a07SSrinivasan Raju case -EPIPE:
36068d57a07SSrinivasan Raju dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status);
36168d57a07SSrinivasan Raju break;
36268d57a07SSrinivasan Raju default:
36368d57a07SSrinivasan Raju dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status);
36468d57a07SSrinivasan Raju return;
36568d57a07SSrinivasan Raju }
36668d57a07SSrinivasan Raju
36768d57a07SSrinivasan Raju plfxlc_mac_tx_to_dev(skb, urb->status);
36868d57a07SSrinivasan Raju plfxlc_send_packet_from_data_queue(usb);
36968d57a07SSrinivasan Raju usb_free_urb(urb);
37068d57a07SSrinivasan Raju }
37168d57a07SSrinivasan Raju
init_usb_rx(struct plfxlc_usb * usb)37268d57a07SSrinivasan Raju static inline void init_usb_rx(struct plfxlc_usb *usb)
37368d57a07SSrinivasan Raju {
37468d57a07SSrinivasan Raju struct plfxlc_usb_rx *rx = &usb->rx;
37568d57a07SSrinivasan Raju
37668d57a07SSrinivasan Raju spin_lock_init(&rx->lock);
37768d57a07SSrinivasan Raju mutex_init(&rx->setup_mutex);
37868d57a07SSrinivasan Raju
37968d57a07SSrinivasan Raju if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH)
38068d57a07SSrinivasan Raju rx->usb_packet_size = 512;
38168d57a07SSrinivasan Raju else
38268d57a07SSrinivasan Raju rx->usb_packet_size = 64;
38368d57a07SSrinivasan Raju
38468d57a07SSrinivasan Raju if (rx->fragment_length != 0)
38568d57a07SSrinivasan Raju dev_dbg(plfxlc_usb_dev(usb), "fragment_length error\n");
38668d57a07SSrinivasan Raju }
38768d57a07SSrinivasan Raju
init_usb_tx(struct plfxlc_usb * usb)38868d57a07SSrinivasan Raju static inline void init_usb_tx(struct plfxlc_usb *usb)
38968d57a07SSrinivasan Raju {
39068d57a07SSrinivasan Raju struct plfxlc_usb_tx *tx = &usb->tx;
39168d57a07SSrinivasan Raju
39268d57a07SSrinivasan Raju spin_lock_init(&tx->lock);
39368d57a07SSrinivasan Raju clear_bit(PLF_BIT_ENABLED, &tx->enabled);
39468d57a07SSrinivasan Raju tx->stopped = 0;
39568d57a07SSrinivasan Raju skb_queue_head_init(&tx->submitted_skbs);
39668d57a07SSrinivasan Raju init_usb_anchor(&tx->submitted);
39768d57a07SSrinivasan Raju }
39868d57a07SSrinivasan Raju
plfxlc_usb_init(struct plfxlc_usb * usb,struct ieee80211_hw * hw,struct usb_interface * intf)39968d57a07SSrinivasan Raju void plfxlc_usb_init(struct plfxlc_usb *usb, struct ieee80211_hw *hw,
40068d57a07SSrinivasan Raju struct usb_interface *intf)
40168d57a07SSrinivasan Raju {
40268d57a07SSrinivasan Raju memset(usb, 0, sizeof(*usb));
40368d57a07SSrinivasan Raju usb->intf = usb_get_intf(intf);
40468d57a07SSrinivasan Raju usb_set_intfdata(usb->intf, hw);
40568d57a07SSrinivasan Raju init_usb_tx(usb);
40668d57a07SSrinivasan Raju init_usb_rx(usb);
40768d57a07SSrinivasan Raju }
40868d57a07SSrinivasan Raju
plfxlc_usb_release(struct plfxlc_usb * usb)40968d57a07SSrinivasan Raju void plfxlc_usb_release(struct plfxlc_usb *usb)
41068d57a07SSrinivasan Raju {
41168d57a07SSrinivasan Raju plfxlc_op_stop(plfxlc_usb_to_hw(usb));
41268d57a07SSrinivasan Raju plfxlc_usb_disable_tx(usb);
41368d57a07SSrinivasan Raju plfxlc_usb_disable_rx(usb);
41468d57a07SSrinivasan Raju usb_set_intfdata(usb->intf, NULL);
41568d57a07SSrinivasan Raju usb_put_intf(usb->intf);
41668d57a07SSrinivasan Raju }
41768d57a07SSrinivasan Raju
plfxlc_speed(enum usb_device_speed speed)41868d57a07SSrinivasan Raju const char *plfxlc_speed(enum usb_device_speed speed)
41968d57a07SSrinivasan Raju {
42068d57a07SSrinivasan Raju switch (speed) {
42168d57a07SSrinivasan Raju case USB_SPEED_LOW:
42268d57a07SSrinivasan Raju return "low";
42368d57a07SSrinivasan Raju case USB_SPEED_FULL:
42468d57a07SSrinivasan Raju return "full";
42568d57a07SSrinivasan Raju case USB_SPEED_HIGH:
42668d57a07SSrinivasan Raju return "high";
42768d57a07SSrinivasan Raju default:
42868d57a07SSrinivasan Raju return "unknown";
42968d57a07SSrinivasan Raju }
43068d57a07SSrinivasan Raju }
43168d57a07SSrinivasan Raju
plfxlc_usb_init_hw(struct plfxlc_usb * usb)43268d57a07SSrinivasan Raju int plfxlc_usb_init_hw(struct plfxlc_usb *usb)
43368d57a07SSrinivasan Raju {
43468d57a07SSrinivasan Raju int r;
43568d57a07SSrinivasan Raju
43668d57a07SSrinivasan Raju r = usb_reset_configuration(plfxlc_usb_to_usbdev(usb));
43768d57a07SSrinivasan Raju if (r) {
43868d57a07SSrinivasan Raju dev_err(plfxlc_usb_dev(usb), "cfg reset failed (%d)\n", r);
43968d57a07SSrinivasan Raju return r;
44068d57a07SSrinivasan Raju }
44168d57a07SSrinivasan Raju return 0;
44268d57a07SSrinivasan Raju }
44368d57a07SSrinivasan Raju
get_usb_req(struct usb_device * udev,void * buffer,u32 buffer_len,enum plf_usb_req_enum usb_req_id,struct plf_usb_req * usb_req)44468d57a07SSrinivasan Raju static void get_usb_req(struct usb_device *udev, void *buffer,
44568d57a07SSrinivasan Raju u32 buffer_len, enum plf_usb_req_enum usb_req_id,
44668d57a07SSrinivasan Raju struct plf_usb_req *usb_req)
44768d57a07SSrinivasan Raju {
44868d57a07SSrinivasan Raju __be32 payload_len_nw = cpu_to_be32(buffer_len + FCS_LEN);
44968d57a07SSrinivasan Raju const u8 *buffer_src_p = buffer;
45068d57a07SSrinivasan Raju u8 *buffer_dst = usb_req->buf;
45168d57a07SSrinivasan Raju u32 temp_usb_len = 0;
45268d57a07SSrinivasan Raju
45368d57a07SSrinivasan Raju usb_req->id = cpu_to_be32(usb_req_id);
45468d57a07SSrinivasan Raju usb_req->len = cpu_to_be32(0);
45568d57a07SSrinivasan Raju
45668d57a07SSrinivasan Raju /* Copy buffer length into the transmitted buffer, as it is important
45768d57a07SSrinivasan Raju * for the Rx MAC to know its exact length.
45868d57a07SSrinivasan Raju */
45968d57a07SSrinivasan Raju if (usb_req->id == cpu_to_be32(USB_REQ_BEACON_WR)) {
46068d57a07SSrinivasan Raju memcpy(buffer_dst, &payload_len_nw, sizeof(payload_len_nw));
46168d57a07SSrinivasan Raju buffer_dst += sizeof(payload_len_nw);
46268d57a07SSrinivasan Raju temp_usb_len += sizeof(payload_len_nw);
46368d57a07SSrinivasan Raju }
46468d57a07SSrinivasan Raju
46568d57a07SSrinivasan Raju memcpy(buffer_dst, buffer_src_p, buffer_len);
46668d57a07SSrinivasan Raju buffer_dst += buffer_len;
46768d57a07SSrinivasan Raju buffer_src_p += buffer_len;
46868d57a07SSrinivasan Raju temp_usb_len += buffer_len;
46968d57a07SSrinivasan Raju
47068d57a07SSrinivasan Raju /* Set the FCS_LEN (4) bytes as 0 for CRC checking. */
47168d57a07SSrinivasan Raju memset(buffer_dst, 0, FCS_LEN);
47268d57a07SSrinivasan Raju buffer_dst += FCS_LEN;
47368d57a07SSrinivasan Raju temp_usb_len += FCS_LEN;
47468d57a07SSrinivasan Raju
47568d57a07SSrinivasan Raju /* Round the packet to be transmitted to 4 bytes. */
47668d57a07SSrinivasan Raju if (temp_usb_len % PURELIFI_BYTE_NUM_ALIGNMENT) {
47768d57a07SSrinivasan Raju memset(buffer_dst, 0, PURELIFI_BYTE_NUM_ALIGNMENT -
47868d57a07SSrinivasan Raju (temp_usb_len %
47968d57a07SSrinivasan Raju PURELIFI_BYTE_NUM_ALIGNMENT));
48068d57a07SSrinivasan Raju buffer_dst += PURELIFI_BYTE_NUM_ALIGNMENT -
48168d57a07SSrinivasan Raju (temp_usb_len %
48268d57a07SSrinivasan Raju PURELIFI_BYTE_NUM_ALIGNMENT);
48368d57a07SSrinivasan Raju temp_usb_len += PURELIFI_BYTE_NUM_ALIGNMENT -
48468d57a07SSrinivasan Raju (temp_usb_len % PURELIFI_BYTE_NUM_ALIGNMENT);
48568d57a07SSrinivasan Raju }
48668d57a07SSrinivasan Raju
48768d57a07SSrinivasan Raju usb_req->len = cpu_to_be32(temp_usb_len);
48868d57a07SSrinivasan Raju }
48968d57a07SSrinivasan Raju
plfxlc_usb_wreq_async(struct plfxlc_usb * usb,const u8 * buffer,int buffer_len,enum plf_usb_req_enum usb_req_id,usb_complete_t complete_fn,void * context)49068d57a07SSrinivasan Raju int plfxlc_usb_wreq_async(struct plfxlc_usb *usb, const u8 *buffer,
49168d57a07SSrinivasan Raju int buffer_len, enum plf_usb_req_enum usb_req_id,
49268d57a07SSrinivasan Raju usb_complete_t complete_fn,
49368d57a07SSrinivasan Raju void *context)
49468d57a07SSrinivasan Raju {
49568d57a07SSrinivasan Raju struct usb_device *udev = interface_to_usbdev(usb->ez_usb);
496*2ed15a3aSDan Carpenter struct urb *urb;
49768d57a07SSrinivasan Raju int r;
49868d57a07SSrinivasan Raju
499*2ed15a3aSDan Carpenter urb = usb_alloc_urb(0, GFP_ATOMIC);
500*2ed15a3aSDan Carpenter if (!urb)
501*2ed15a3aSDan Carpenter return -ENOMEM;
50268d57a07SSrinivasan Raju usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
50368d57a07SSrinivasan Raju (void *)buffer, buffer_len, complete_fn, context);
50468d57a07SSrinivasan Raju
50568d57a07SSrinivasan Raju r = usb_submit_urb(urb, GFP_ATOMIC);
50668d57a07SSrinivasan Raju if (r)
50768d57a07SSrinivasan Raju dev_err(&udev->dev, "Async write submit failed (%d)\n", r);
50868d57a07SSrinivasan Raju
50968d57a07SSrinivasan Raju return r;
51068d57a07SSrinivasan Raju }
51168d57a07SSrinivasan Raju
plfxlc_usb_wreq(struct usb_interface * ez_usb,void * buffer,int buffer_len,enum plf_usb_req_enum usb_req_id)51268d57a07SSrinivasan Raju int plfxlc_usb_wreq(struct usb_interface *ez_usb, void *buffer, int buffer_len,
51368d57a07SSrinivasan Raju enum plf_usb_req_enum usb_req_id)
51468d57a07SSrinivasan Raju {
51568d57a07SSrinivasan Raju struct usb_device *udev = interface_to_usbdev(ez_usb);
51668d57a07SSrinivasan Raju unsigned char *dma_buffer = NULL;
51768d57a07SSrinivasan Raju struct plf_usb_req usb_req;
51868d57a07SSrinivasan Raju int usb_bulk_msg_len;
51968d57a07SSrinivasan Raju int actual_length;
52068d57a07SSrinivasan Raju int r;
52168d57a07SSrinivasan Raju
52268d57a07SSrinivasan Raju get_usb_req(udev, buffer, buffer_len, usb_req_id, &usb_req);
52368d57a07SSrinivasan Raju usb_bulk_msg_len = sizeof(__le32) + sizeof(__le32) +
52468d57a07SSrinivasan Raju be32_to_cpu(usb_req.len);
52568d57a07SSrinivasan Raju
52668d57a07SSrinivasan Raju dma_buffer = kmemdup(&usb_req, usb_bulk_msg_len, GFP_KERNEL);
52768d57a07SSrinivasan Raju
52868d57a07SSrinivasan Raju if (!dma_buffer) {
52968d57a07SSrinivasan Raju r = -ENOMEM;
53068d57a07SSrinivasan Raju goto error;
53168d57a07SSrinivasan Raju }
53268d57a07SSrinivasan Raju
53368d57a07SSrinivasan Raju r = usb_bulk_msg(udev,
53468d57a07SSrinivasan Raju usb_sndbulkpipe(udev, EP_DATA_OUT),
53568d57a07SSrinivasan Raju dma_buffer, usb_bulk_msg_len,
53668d57a07SSrinivasan Raju &actual_length, USB_BULK_MSG_TIMEOUT_MS);
53768d57a07SSrinivasan Raju kfree(dma_buffer);
53868d57a07SSrinivasan Raju error:
53968d57a07SSrinivasan Raju if (r) {
54068d57a07SSrinivasan Raju r = -ENOMEM;
54168d57a07SSrinivasan Raju dev_err(&udev->dev, "usb_bulk_msg failed (%d)\n", r);
54268d57a07SSrinivasan Raju }
54368d57a07SSrinivasan Raju
54468d57a07SSrinivasan Raju return r;
54568d57a07SSrinivasan Raju }
54668d57a07SSrinivasan Raju
slif_data_plane_sap_timer_callb(struct timer_list * t)54768d57a07SSrinivasan Raju static void slif_data_plane_sap_timer_callb(struct timer_list *t)
54868d57a07SSrinivasan Raju {
54968d57a07SSrinivasan Raju struct plfxlc_usb *usb = from_timer(usb, t, tx.tx_retry_timer);
55068d57a07SSrinivasan Raju
55168d57a07SSrinivasan Raju plfxlc_send_packet_from_data_queue(usb);
55268d57a07SSrinivasan Raju timer_setup(&usb->tx.tx_retry_timer,
55368d57a07SSrinivasan Raju slif_data_plane_sap_timer_callb, 0);
55468d57a07SSrinivasan Raju mod_timer(&usb->tx.tx_retry_timer, jiffies + TX_RETRY_BACKOFF_JIFF);
55568d57a07SSrinivasan Raju }
55668d57a07SSrinivasan Raju
sta_queue_cleanup_timer_callb(struct timer_list * t)55768d57a07SSrinivasan Raju static void sta_queue_cleanup_timer_callb(struct timer_list *t)
55868d57a07SSrinivasan Raju {
55968d57a07SSrinivasan Raju struct plfxlc_usb *usb = from_timer(usb, t, sta_queue_cleanup);
56068d57a07SSrinivasan Raju struct plfxlc_usb_tx *tx = &usb->tx;
56168d57a07SSrinivasan Raju int sidx;
56268d57a07SSrinivasan Raju
56368d57a07SSrinivasan Raju for (sidx = 0; sidx < MAX_STA_NUM - 1; sidx++) {
56468d57a07SSrinivasan Raju if (!(tx->station[sidx].flag & STATION_CONNECTED_FLAG))
56568d57a07SSrinivasan Raju continue;
56668d57a07SSrinivasan Raju if (tx->station[sidx].flag & STATION_HEARTBEAT_FLAG) {
56768d57a07SSrinivasan Raju tx->station[sidx].flag ^= STATION_HEARTBEAT_FLAG;
56868d57a07SSrinivasan Raju } else {
56970c898d4SXu Qiang eth_zero_addr(tx->station[sidx].mac);
57068d57a07SSrinivasan Raju tx->station[sidx].flag = 0;
57168d57a07SSrinivasan Raju }
57268d57a07SSrinivasan Raju }
57368d57a07SSrinivasan Raju timer_setup(&usb->sta_queue_cleanup,
57468d57a07SSrinivasan Raju sta_queue_cleanup_timer_callb, 0);
57568d57a07SSrinivasan Raju mod_timer(&usb->sta_queue_cleanup, jiffies + STA_QUEUE_CLEANUP_JIFF);
57668d57a07SSrinivasan Raju }
57768d57a07SSrinivasan Raju
probe(struct usb_interface * intf,const struct usb_device_id * id)57868d57a07SSrinivasan Raju static int probe(struct usb_interface *intf,
57968d57a07SSrinivasan Raju const struct usb_device_id *id)
58068d57a07SSrinivasan Raju {
58168d57a07SSrinivasan Raju u8 serial_number[PURELIFI_SERIAL_LEN];
58268d57a07SSrinivasan Raju struct ieee80211_hw *hw = NULL;
58368d57a07SSrinivasan Raju struct plfxlc_usb_tx *tx;
58468d57a07SSrinivasan Raju struct plfxlc_chip *chip;
58568d57a07SSrinivasan Raju struct plfxlc_usb *usb;
58668d57a07SSrinivasan Raju u8 hw_address[ETH_ALEN];
58768d57a07SSrinivasan Raju unsigned int i;
58868d57a07SSrinivasan Raju int r = 0;
58968d57a07SSrinivasan Raju
59068d57a07SSrinivasan Raju hw = plfxlc_mac_alloc_hw(intf);
59168d57a07SSrinivasan Raju
59268d57a07SSrinivasan Raju if (!hw) {
59368d57a07SSrinivasan Raju r = -ENOMEM;
59468d57a07SSrinivasan Raju goto error;
59568d57a07SSrinivasan Raju }
59668d57a07SSrinivasan Raju
59768d57a07SSrinivasan Raju chip = &plfxlc_hw_mac(hw)->chip;
59868d57a07SSrinivasan Raju usb = &chip->usb;
59968d57a07SSrinivasan Raju usb->ez_usb = intf;
60068d57a07SSrinivasan Raju tx = &usb->tx;
60168d57a07SSrinivasan Raju
60268d57a07SSrinivasan Raju r = plfxlc_upload_mac_and_serial(intf, hw_address, serial_number);
60368d57a07SSrinivasan Raju if (r) {
60468d57a07SSrinivasan Raju dev_err(&intf->dev, "MAC and Serial upload failed (%d)\n", r);
60568d57a07SSrinivasan Raju goto error;
60668d57a07SSrinivasan Raju }
60768d57a07SSrinivasan Raju
60868d57a07SSrinivasan Raju chip->unit_type = STA;
60968d57a07SSrinivasan Raju dev_err(&intf->dev, "Unit type is station");
61068d57a07SSrinivasan Raju
61168d57a07SSrinivasan Raju r = plfxlc_mac_preinit_hw(hw, hw_address);
61268d57a07SSrinivasan Raju if (r) {
61368d57a07SSrinivasan Raju dev_err(&intf->dev, "Init mac failed (%d)\n", r);
61468d57a07SSrinivasan Raju goto error;
61568d57a07SSrinivasan Raju }
61668d57a07SSrinivasan Raju
61768d57a07SSrinivasan Raju r = ieee80211_register_hw(hw);
61868d57a07SSrinivasan Raju if (r) {
61968d57a07SSrinivasan Raju dev_err(&intf->dev, "Register device failed (%d)\n", r);
62068d57a07SSrinivasan Raju goto error;
62168d57a07SSrinivasan Raju }
62268d57a07SSrinivasan Raju
62368d57a07SSrinivasan Raju if ((le16_to_cpu(interface_to_usbdev(intf)->descriptor.idVendor) ==
62468d57a07SSrinivasan Raju PURELIFI_XL_VENDOR_ID_0) &&
62568d57a07SSrinivasan Raju (le16_to_cpu(interface_to_usbdev(intf)->descriptor.idProduct) ==
62668d57a07SSrinivasan Raju PURELIFI_XL_PRODUCT_ID_0)) {
62768d57a07SSrinivasan Raju r = plfxlc_download_xl_firmware(intf);
62868d57a07SSrinivasan Raju } else {
62968d57a07SSrinivasan Raju r = plfxlc_download_fpga(intf);
63068d57a07SSrinivasan Raju }
63168d57a07SSrinivasan Raju if (r != 0) {
63268d57a07SSrinivasan Raju dev_err(&intf->dev, "FPGA download failed (%d)\n", r);
63368d57a07SSrinivasan Raju goto error;
63468d57a07SSrinivasan Raju }
63568d57a07SSrinivasan Raju
63668d57a07SSrinivasan Raju tx->mac_fifo_full = 0;
63768d57a07SSrinivasan Raju spin_lock_init(&tx->lock);
63868d57a07SSrinivasan Raju
63968d57a07SSrinivasan Raju msleep(PLF_MSLEEP_TIME);
64068d57a07SSrinivasan Raju r = plfxlc_usb_init_hw(usb);
64168d57a07SSrinivasan Raju if (r < 0) {
64268d57a07SSrinivasan Raju dev_err(&intf->dev, "usb_init_hw failed (%d)\n", r);
64368d57a07SSrinivasan Raju goto error;
64468d57a07SSrinivasan Raju }
64568d57a07SSrinivasan Raju
64668d57a07SSrinivasan Raju msleep(PLF_MSLEEP_TIME);
64768d57a07SSrinivasan Raju r = plfxlc_chip_switch_radio(chip, PLFXLC_RADIO_ON);
64868d57a07SSrinivasan Raju if (r < 0) {
64968d57a07SSrinivasan Raju dev_dbg(&intf->dev, "chip_switch_radio_on failed (%d)\n", r);
65068d57a07SSrinivasan Raju goto error;
65168d57a07SSrinivasan Raju }
65268d57a07SSrinivasan Raju
65368d57a07SSrinivasan Raju msleep(PLF_MSLEEP_TIME);
65468d57a07SSrinivasan Raju r = plfxlc_chip_set_rate(chip, 8);
65568d57a07SSrinivasan Raju if (r < 0) {
65668d57a07SSrinivasan Raju dev_dbg(&intf->dev, "chip_set_rate failed (%d)\n", r);
65768d57a07SSrinivasan Raju goto error;
65868d57a07SSrinivasan Raju }
65968d57a07SSrinivasan Raju
66068d57a07SSrinivasan Raju msleep(PLF_MSLEEP_TIME);
66168d57a07SSrinivasan Raju r = plfxlc_usb_wreq(usb->ez_usb,
66268d57a07SSrinivasan Raju hw_address, ETH_ALEN, USB_REQ_MAC_WR);
66368d57a07SSrinivasan Raju if (r < 0) {
66468d57a07SSrinivasan Raju dev_dbg(&intf->dev, "MAC_WR failure (%d)\n", r);
66568d57a07SSrinivasan Raju goto error;
66668d57a07SSrinivasan Raju }
66768d57a07SSrinivasan Raju
66868d57a07SSrinivasan Raju plfxlc_chip_enable_rxtx(chip);
66968d57a07SSrinivasan Raju
67068d57a07SSrinivasan Raju /* Initialise the data plane Tx queue */
67168d57a07SSrinivasan Raju for (i = 0; i < MAX_STA_NUM; i++) {
67268d57a07SSrinivasan Raju skb_queue_head_init(&tx->station[i].data_list);
67368d57a07SSrinivasan Raju tx->station[i].flag = 0;
67468d57a07SSrinivasan Raju }
67568d57a07SSrinivasan Raju
67668d57a07SSrinivasan Raju tx->station[STA_BROADCAST_INDEX].flag |= STATION_CONNECTED_FLAG;
67768d57a07SSrinivasan Raju for (i = 0; i < ETH_ALEN; i++)
67868d57a07SSrinivasan Raju tx->station[STA_BROADCAST_INDEX].mac[i] = 0xFF;
67968d57a07SSrinivasan Raju
68068d57a07SSrinivasan Raju timer_setup(&tx->tx_retry_timer, slif_data_plane_sap_timer_callb, 0);
68168d57a07SSrinivasan Raju tx->tx_retry_timer.expires = jiffies + TX_RETRY_BACKOFF_JIFF;
68268d57a07SSrinivasan Raju add_timer(&tx->tx_retry_timer);
68368d57a07SSrinivasan Raju
68468d57a07SSrinivasan Raju timer_setup(&usb->sta_queue_cleanup,
68568d57a07SSrinivasan Raju sta_queue_cleanup_timer_callb, 0);
68668d57a07SSrinivasan Raju usb->sta_queue_cleanup.expires = jiffies + STA_QUEUE_CLEANUP_JIFF;
68768d57a07SSrinivasan Raju add_timer(&usb->sta_queue_cleanup);
68868d57a07SSrinivasan Raju
68968d57a07SSrinivasan Raju plfxlc_mac_init_hw(hw);
69068d57a07SSrinivasan Raju usb->initialized = true;
69168d57a07SSrinivasan Raju return 0;
69268d57a07SSrinivasan Raju error:
69368d57a07SSrinivasan Raju if (hw) {
69468d57a07SSrinivasan Raju plfxlc_mac_release(plfxlc_hw_mac(hw));
69568d57a07SSrinivasan Raju ieee80211_unregister_hw(hw);
69668d57a07SSrinivasan Raju ieee80211_free_hw(hw);
69768d57a07SSrinivasan Raju }
69868d57a07SSrinivasan Raju dev_err(&intf->dev, "pureLifi:Device error");
69968d57a07SSrinivasan Raju return r;
70068d57a07SSrinivasan Raju }
70168d57a07SSrinivasan Raju
disconnect(struct usb_interface * intf)70268d57a07SSrinivasan Raju static void disconnect(struct usb_interface *intf)
70368d57a07SSrinivasan Raju {
70468d57a07SSrinivasan Raju struct ieee80211_hw *hw = plfxlc_intf_to_hw(intf);
70568d57a07SSrinivasan Raju struct plfxlc_mac *mac;
70668d57a07SSrinivasan Raju struct plfxlc_usb *usb;
70768d57a07SSrinivasan Raju
70868d57a07SSrinivasan Raju /* Either something really bad happened, or
70968d57a07SSrinivasan Raju * we're just dealing with a DEVICE_INSTALLER.
71068d57a07SSrinivasan Raju */
71168d57a07SSrinivasan Raju if (!hw)
71268d57a07SSrinivasan Raju return;
71368d57a07SSrinivasan Raju
71468d57a07SSrinivasan Raju mac = plfxlc_hw_mac(hw);
71568d57a07SSrinivasan Raju usb = &mac->chip.usb;
71668d57a07SSrinivasan Raju
71768d57a07SSrinivasan Raju del_timer_sync(&usb->tx.tx_retry_timer);
71868d57a07SSrinivasan Raju del_timer_sync(&usb->sta_queue_cleanup);
71968d57a07SSrinivasan Raju
72068d57a07SSrinivasan Raju ieee80211_unregister_hw(hw);
72168d57a07SSrinivasan Raju
72268d57a07SSrinivasan Raju plfxlc_chip_disable_rxtx(&mac->chip);
72368d57a07SSrinivasan Raju
72468d57a07SSrinivasan Raju /* If the disconnect has been caused by a removal of the
72568d57a07SSrinivasan Raju * driver module, the reset allows reloading of the driver. If the
72668d57a07SSrinivasan Raju * reset will not be executed here, the upload of the firmware in the
72768d57a07SSrinivasan Raju * probe function caused by the reloading of the driver will fail.
72868d57a07SSrinivasan Raju */
72968d57a07SSrinivasan Raju usb_reset_device(interface_to_usbdev(intf));
73068d57a07SSrinivasan Raju
73168d57a07SSrinivasan Raju plfxlc_mac_release(mac);
73268d57a07SSrinivasan Raju ieee80211_free_hw(hw);
73368d57a07SSrinivasan Raju }
73468d57a07SSrinivasan Raju
plfxlc_usb_resume(struct plfxlc_usb * usb)73568d57a07SSrinivasan Raju static void plfxlc_usb_resume(struct plfxlc_usb *usb)
73668d57a07SSrinivasan Raju {
73768d57a07SSrinivasan Raju struct plfxlc_mac *mac = plfxlc_usb_to_mac(usb);
73868d57a07SSrinivasan Raju int r;
73968d57a07SSrinivasan Raju
74068d57a07SSrinivasan Raju r = plfxlc_op_start(plfxlc_usb_to_hw(usb));
74168d57a07SSrinivasan Raju if (r < 0) {
74268d57a07SSrinivasan Raju dev_warn(plfxlc_usb_dev(usb),
74368d57a07SSrinivasan Raju "Device resume failed (%d)\n", r);
74468d57a07SSrinivasan Raju
74568d57a07SSrinivasan Raju if (usb->was_running)
74668d57a07SSrinivasan Raju set_bit(PURELIFI_DEVICE_RUNNING, &mac->flags);
74768d57a07SSrinivasan Raju
74868d57a07SSrinivasan Raju usb_queue_reset_device(usb->intf);
74968d57a07SSrinivasan Raju return;
75068d57a07SSrinivasan Raju }
75168d57a07SSrinivasan Raju
75268d57a07SSrinivasan Raju if (mac->type != NL80211_IFTYPE_UNSPECIFIED) {
75368d57a07SSrinivasan Raju r = plfxlc_restore_settings(mac);
75468d57a07SSrinivasan Raju if (r < 0) {
75568d57a07SSrinivasan Raju dev_dbg(plfxlc_usb_dev(usb),
75668d57a07SSrinivasan Raju "Restore failed (%d)\n", r);
75768d57a07SSrinivasan Raju return;
75868d57a07SSrinivasan Raju }
75968d57a07SSrinivasan Raju }
76068d57a07SSrinivasan Raju }
76168d57a07SSrinivasan Raju
plfxlc_usb_stop(struct plfxlc_usb * usb)76268d57a07SSrinivasan Raju static void plfxlc_usb_stop(struct plfxlc_usb *usb)
76368d57a07SSrinivasan Raju {
76468d57a07SSrinivasan Raju plfxlc_op_stop(plfxlc_usb_to_hw(usb));
76568d57a07SSrinivasan Raju plfxlc_usb_disable_tx(usb);
76668d57a07SSrinivasan Raju plfxlc_usb_disable_rx(usb);
76768d57a07SSrinivasan Raju
76868d57a07SSrinivasan Raju usb->initialized = false;
76968d57a07SSrinivasan Raju }
77068d57a07SSrinivasan Raju
pre_reset(struct usb_interface * intf)77168d57a07SSrinivasan Raju static int pre_reset(struct usb_interface *intf)
77268d57a07SSrinivasan Raju {
77368d57a07SSrinivasan Raju struct ieee80211_hw *hw = usb_get_intfdata(intf);
77468d57a07SSrinivasan Raju struct plfxlc_mac *mac;
77568d57a07SSrinivasan Raju struct plfxlc_usb *usb;
77668d57a07SSrinivasan Raju
77768d57a07SSrinivasan Raju if (!hw || intf->condition != USB_INTERFACE_BOUND)
77868d57a07SSrinivasan Raju return 0;
77968d57a07SSrinivasan Raju
78068d57a07SSrinivasan Raju mac = plfxlc_hw_mac(hw);
78168d57a07SSrinivasan Raju usb = &mac->chip.usb;
78268d57a07SSrinivasan Raju
78368d57a07SSrinivasan Raju usb->was_running = test_bit(PURELIFI_DEVICE_RUNNING, &mac->flags);
78468d57a07SSrinivasan Raju
78568d57a07SSrinivasan Raju plfxlc_usb_stop(usb);
78668d57a07SSrinivasan Raju
78768d57a07SSrinivasan Raju return 0;
78868d57a07SSrinivasan Raju }
78968d57a07SSrinivasan Raju
post_reset(struct usb_interface * intf)79068d57a07SSrinivasan Raju static int post_reset(struct usb_interface *intf)
79168d57a07SSrinivasan Raju {
79268d57a07SSrinivasan Raju struct ieee80211_hw *hw = usb_get_intfdata(intf);
79368d57a07SSrinivasan Raju struct plfxlc_mac *mac;
79468d57a07SSrinivasan Raju struct plfxlc_usb *usb;
79568d57a07SSrinivasan Raju
79668d57a07SSrinivasan Raju if (!hw || intf->condition != USB_INTERFACE_BOUND)
79768d57a07SSrinivasan Raju return 0;
79868d57a07SSrinivasan Raju
79968d57a07SSrinivasan Raju mac = plfxlc_hw_mac(hw);
80068d57a07SSrinivasan Raju usb = &mac->chip.usb;
80168d57a07SSrinivasan Raju
80268d57a07SSrinivasan Raju if (usb->was_running)
80368d57a07SSrinivasan Raju plfxlc_usb_resume(usb);
80468d57a07SSrinivasan Raju
80568d57a07SSrinivasan Raju return 0;
80668d57a07SSrinivasan Raju }
80768d57a07SSrinivasan Raju
80868d57a07SSrinivasan Raju #ifdef CONFIG_PM
80968d57a07SSrinivasan Raju
get_plfxlc_usb(struct usb_interface * intf)81068d57a07SSrinivasan Raju static struct plfxlc_usb *get_plfxlc_usb(struct usb_interface *intf)
81168d57a07SSrinivasan Raju {
81268d57a07SSrinivasan Raju struct ieee80211_hw *hw = plfxlc_intf_to_hw(intf);
81368d57a07SSrinivasan Raju struct plfxlc_mac *mac;
81468d57a07SSrinivasan Raju
81568d57a07SSrinivasan Raju /* Either something really bad happened, or
81668d57a07SSrinivasan Raju * we're just dealing with a DEVICE_INSTALLER.
81768d57a07SSrinivasan Raju */
81868d57a07SSrinivasan Raju if (!hw)
81968d57a07SSrinivasan Raju return NULL;
82068d57a07SSrinivasan Raju
82168d57a07SSrinivasan Raju mac = plfxlc_hw_mac(hw);
82268d57a07SSrinivasan Raju return &mac->chip.usb;
82368d57a07SSrinivasan Raju }
82468d57a07SSrinivasan Raju
suspend(struct usb_interface * interface,pm_message_t message)82568d57a07SSrinivasan Raju static int suspend(struct usb_interface *interface,
82668d57a07SSrinivasan Raju pm_message_t message)
82768d57a07SSrinivasan Raju {
82868d57a07SSrinivasan Raju struct plfxlc_usb *pl = get_plfxlc_usb(interface);
82968d57a07SSrinivasan Raju struct plfxlc_mac *mac = plfxlc_usb_to_mac(pl);
83068d57a07SSrinivasan Raju
8310c7ab953SJakub Kicinski if (!pl)
83268d57a07SSrinivasan Raju return -ENODEV;
83368d57a07SSrinivasan Raju if (pl->initialized == 0)
83468d57a07SSrinivasan Raju return 0;
83568d57a07SSrinivasan Raju pl->was_running = test_bit(PURELIFI_DEVICE_RUNNING, &mac->flags);
83668d57a07SSrinivasan Raju plfxlc_usb_stop(pl);
83768d57a07SSrinivasan Raju return 0;
83868d57a07SSrinivasan Raju }
83968d57a07SSrinivasan Raju
resume(struct usb_interface * interface)84068d57a07SSrinivasan Raju static int resume(struct usb_interface *interface)
84168d57a07SSrinivasan Raju {
84268d57a07SSrinivasan Raju struct plfxlc_usb *pl = get_plfxlc_usb(interface);
84368d57a07SSrinivasan Raju
8440c7ab953SJakub Kicinski if (!pl)
84568d57a07SSrinivasan Raju return -ENODEV;
84668d57a07SSrinivasan Raju if (pl->was_running)
84768d57a07SSrinivasan Raju plfxlc_usb_resume(pl);
84868d57a07SSrinivasan Raju return 0;
84968d57a07SSrinivasan Raju }
85068d57a07SSrinivasan Raju
85168d57a07SSrinivasan Raju #endif
85268d57a07SSrinivasan Raju
85368d57a07SSrinivasan Raju static struct usb_driver driver = {
85468d57a07SSrinivasan Raju .name = KBUILD_MODNAME,
85568d57a07SSrinivasan Raju .id_table = usb_ids,
85668d57a07SSrinivasan Raju .probe = probe,
85768d57a07SSrinivasan Raju .disconnect = disconnect,
85868d57a07SSrinivasan Raju .pre_reset = pre_reset,
85968d57a07SSrinivasan Raju .post_reset = post_reset,
86068d57a07SSrinivasan Raju #ifdef CONFIG_PM
86168d57a07SSrinivasan Raju .suspend = suspend,
86268d57a07SSrinivasan Raju .resume = resume,
86368d57a07SSrinivasan Raju #endif
86468d57a07SSrinivasan Raju .disable_hub_initiated_lpm = 1,
86568d57a07SSrinivasan Raju };
86668d57a07SSrinivasan Raju
usb_init(void)86768d57a07SSrinivasan Raju static int __init usb_init(void)
86868d57a07SSrinivasan Raju {
86968d57a07SSrinivasan Raju int r;
87068d57a07SSrinivasan Raju
87168d57a07SSrinivasan Raju r = usb_register(&driver);
87268d57a07SSrinivasan Raju if (r) {
87368d57a07SSrinivasan Raju pr_err("%s usb_register() failed %d\n", driver.name, r);
87468d57a07SSrinivasan Raju return r;
87568d57a07SSrinivasan Raju }
87668d57a07SSrinivasan Raju
87768d57a07SSrinivasan Raju pr_debug("Driver initialized :%s\n", driver.name);
87868d57a07SSrinivasan Raju return 0;
87968d57a07SSrinivasan Raju }
88068d57a07SSrinivasan Raju
usb_exit(void)88168d57a07SSrinivasan Raju static void __exit usb_exit(void)
88268d57a07SSrinivasan Raju {
88368d57a07SSrinivasan Raju usb_deregister(&driver);
88468d57a07SSrinivasan Raju pr_debug("%s %s\n", driver.name, __func__);
88568d57a07SSrinivasan Raju }
88668d57a07SSrinivasan Raju
88768d57a07SSrinivasan Raju MODULE_LICENSE("GPL");
88868d57a07SSrinivasan Raju MODULE_DESCRIPTION("USB driver for pureLiFi devices");
88968d57a07SSrinivasan Raju MODULE_AUTHOR("pureLiFi");
89068d57a07SSrinivasan Raju MODULE_VERSION("1.0");
89168d57a07SSrinivasan Raju MODULE_FIRMWARE("plfxlc/lifi-x.bin");
89268d57a07SSrinivasan Raju MODULE_DEVICE_TABLE(usb, usb_ids);
89368d57a07SSrinivasan Raju
89468d57a07SSrinivasan Raju module_init(usb_init);
89568d57a07SSrinivasan Raju module_exit(usb_exit);
896