162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2021 pureLiFi 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/init.h> 862306a36Sopenharmony_ci#include <linux/device.h> 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/skbuff.h> 1262306a36Sopenharmony_ci#include <linux/usb.h> 1362306a36Sopenharmony_ci#include <linux/workqueue.h> 1462306a36Sopenharmony_ci#include <linux/proc_fs.h> 1562306a36Sopenharmony_ci#include <linux/fs.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <net/mac80211.h> 1962306a36Sopenharmony_ci#include <asm/unaligned.h> 2062306a36Sopenharmony_ci#include <linux/sysfs.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "mac.h" 2362306a36Sopenharmony_ci#include "usb.h" 2462306a36Sopenharmony_ci#include "chip.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const struct usb_device_id usb_ids[] = { 2762306a36Sopenharmony_ci { USB_DEVICE(PURELIFI_X_VENDOR_ID_0, PURELIFI_X_PRODUCT_ID_0), 2862306a36Sopenharmony_ci .driver_info = DEVICE_LIFI_X }, 2962306a36Sopenharmony_ci { USB_DEVICE(PURELIFI_XC_VENDOR_ID_0, PURELIFI_XC_PRODUCT_ID_0), 3062306a36Sopenharmony_ci .driver_info = DEVICE_LIFI_XC }, 3162306a36Sopenharmony_ci { USB_DEVICE(PURELIFI_XL_VENDOR_ID_0, PURELIFI_XL_PRODUCT_ID_0), 3262306a36Sopenharmony_ci .driver_info = DEVICE_LIFI_XL }, 3362306a36Sopenharmony_ci {} 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_civoid plfxlc_send_packet_from_data_queue(struct plfxlc_usb *usb) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct plfxlc_usb_tx *tx = &usb->tx; 3962306a36Sopenharmony_ci struct sk_buff *skb = NULL; 4062306a36Sopenharmony_ci unsigned long flags; 4162306a36Sopenharmony_ci u8 last_served_sidx; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci spin_lock_irqsave(&tx->lock, flags); 4462306a36Sopenharmony_ci last_served_sidx = usb->sidx; 4562306a36Sopenharmony_ci do { 4662306a36Sopenharmony_ci usb->sidx = (usb->sidx + 1) % MAX_STA_NUM; 4762306a36Sopenharmony_ci if (!(tx->station[usb->sidx].flag & STATION_CONNECTED_FLAG)) 4862306a36Sopenharmony_ci continue; 4962306a36Sopenharmony_ci if (!(tx->station[usb->sidx].flag & STATION_FIFO_FULL_FLAG)) 5062306a36Sopenharmony_ci skb = skb_peek(&tx->station[usb->sidx].data_list); 5162306a36Sopenharmony_ci } while ((usb->sidx != last_served_sidx) && (!skb)); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (skb) { 5462306a36Sopenharmony_ci skb = skb_dequeue(&tx->station[usb->sidx].data_list); 5562306a36Sopenharmony_ci plfxlc_usb_wreq_async(usb, skb->data, skb->len, USB_REQ_DATA_TX, 5662306a36Sopenharmony_ci plfxlc_tx_urb_complete, skb); 5762306a36Sopenharmony_ci if (skb_queue_len(&tx->station[usb->sidx].data_list) <= 60) 5862306a36Sopenharmony_ci ieee80211_wake_queues(plfxlc_usb_to_hw(usb)); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->lock, flags); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void handle_rx_packet(struct plfxlc_usb *usb, const u8 *buffer, 6462306a36Sopenharmony_ci unsigned int length) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci plfxlc_mac_rx(plfxlc_usb_to_hw(usb), buffer, length); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void rx_urb_complete(struct urb *urb) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct plfxlc_usb_tx *tx; 7262306a36Sopenharmony_ci struct plfxlc_usb *usb; 7362306a36Sopenharmony_ci unsigned int length; 7462306a36Sopenharmony_ci const u8 *buffer; 7562306a36Sopenharmony_ci u16 status; 7662306a36Sopenharmony_ci u8 sidx; 7762306a36Sopenharmony_ci int r; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!urb) { 8062306a36Sopenharmony_ci pr_err("urb is NULL\n"); 8162306a36Sopenharmony_ci return; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci if (!urb->context) { 8462306a36Sopenharmony_ci pr_err("urb ctx is NULL\n"); 8562306a36Sopenharmony_ci return; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci usb = urb->context; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (usb->initialized != 1) { 9062306a36Sopenharmony_ci pr_err("usb is not initialized\n"); 9162306a36Sopenharmony_ci return; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci tx = &usb->tx; 9562306a36Sopenharmony_ci switch (urb->status) { 9662306a36Sopenharmony_ci case 0: 9762306a36Sopenharmony_ci break; 9862306a36Sopenharmony_ci case -ESHUTDOWN: 9962306a36Sopenharmony_ci case -EINVAL: 10062306a36Sopenharmony_ci case -ENODEV: 10162306a36Sopenharmony_ci case -ENOENT: 10262306a36Sopenharmony_ci case -ECONNRESET: 10362306a36Sopenharmony_ci case -EPIPE: 10462306a36Sopenharmony_ci dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status); 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci default: 10762306a36Sopenharmony_ci dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status); 10862306a36Sopenharmony_ci if (tx->submitted_urbs++ < PURELIFI_URB_RETRY_MAX) { 10962306a36Sopenharmony_ci dev_dbg(plfxlc_urb_dev(urb), "urb %p resubmit %d", urb, 11062306a36Sopenharmony_ci tx->submitted_urbs++); 11162306a36Sopenharmony_ci goto resubmit; 11262306a36Sopenharmony_ci } else { 11362306a36Sopenharmony_ci dev_dbg(plfxlc_urb_dev(urb), "urb %p max resubmits reached", urb); 11462306a36Sopenharmony_ci tx->submitted_urbs = 0; 11562306a36Sopenharmony_ci return; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci buffer = urb->transfer_buffer; 12062306a36Sopenharmony_ci length = le32_to_cpu(*(__le32 *)(buffer + sizeof(struct rx_status))) 12162306a36Sopenharmony_ci + sizeof(u32); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (urb->actual_length != (PLF_MSG_STATUS_OFFSET + 1)) { 12462306a36Sopenharmony_ci if (usb->initialized && usb->link_up) 12562306a36Sopenharmony_ci handle_rx_packet(usb, buffer, length); 12662306a36Sopenharmony_ci goto resubmit; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci status = buffer[PLF_MSG_STATUS_OFFSET]; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci switch (status) { 13262306a36Sopenharmony_ci case STATION_FIFO_ALMOST_FULL_NOT_MESSAGE: 13362306a36Sopenharmony_ci dev_dbg(&usb->intf->dev, 13462306a36Sopenharmony_ci "FIFO full not packet receipt\n"); 13562306a36Sopenharmony_ci tx->mac_fifo_full = 1; 13662306a36Sopenharmony_ci for (sidx = 0; sidx < MAX_STA_NUM; sidx++) 13762306a36Sopenharmony_ci tx->station[sidx].flag |= STATION_FIFO_FULL_FLAG; 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci case STATION_FIFO_ALMOST_FULL_MESSAGE: 14062306a36Sopenharmony_ci dev_dbg(&usb->intf->dev, "FIFO full packet receipt\n"); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci for (sidx = 0; sidx < MAX_STA_NUM; sidx++) 14362306a36Sopenharmony_ci tx->station[sidx].flag &= STATION_ACTIVE_FLAG; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci plfxlc_send_packet_from_data_queue(usb); 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci case STATION_CONNECT_MESSAGE: 14862306a36Sopenharmony_ci usb->link_up = 1; 14962306a36Sopenharmony_ci dev_dbg(&usb->intf->dev, "ST_CONNECT_MSG packet receipt\n"); 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci case STATION_DISCONNECT_MESSAGE: 15262306a36Sopenharmony_ci usb->link_up = 0; 15362306a36Sopenharmony_ci dev_dbg(&usb->intf->dev, "ST_DISCONN_MSG packet receipt\n"); 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci default: 15662306a36Sopenharmony_ci dev_dbg(&usb->intf->dev, "Unknown packet receipt\n"); 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciresubmit: 16162306a36Sopenharmony_ci r = usb_submit_urb(urb, GFP_ATOMIC); 16262306a36Sopenharmony_ci if (r) 16362306a36Sopenharmony_ci dev_dbg(plfxlc_urb_dev(urb), "urb %p resubmit fail (%d)\n", urb, r); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic struct urb *alloc_rx_urb(struct plfxlc_usb *usb) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct usb_device *udev = plfxlc_usb_to_usbdev(usb); 16962306a36Sopenharmony_ci struct urb *urb; 17062306a36Sopenharmony_ci void *buffer; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 17362306a36Sopenharmony_ci if (!urb) 17462306a36Sopenharmony_ci return NULL; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL, 17762306a36Sopenharmony_ci &urb->transfer_dma); 17862306a36Sopenharmony_ci if (!buffer) { 17962306a36Sopenharmony_ci usb_free_urb(urb); 18062306a36Sopenharmony_ci return NULL; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN), 18462306a36Sopenharmony_ci buffer, USB_MAX_RX_SIZE, 18562306a36Sopenharmony_ci rx_urb_complete, usb); 18662306a36Sopenharmony_ci urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return urb; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void free_rx_urb(struct urb *urb) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci if (!urb) 19462306a36Sopenharmony_ci return; 19562306a36Sopenharmony_ci usb_free_coherent(urb->dev, urb->transfer_buffer_length, 19662306a36Sopenharmony_ci urb->transfer_buffer, urb->transfer_dma); 19762306a36Sopenharmony_ci usb_free_urb(urb); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int __lf_x_usb_enable_rx(struct plfxlc_usb *usb) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct plfxlc_usb_rx *rx = &usb->rx; 20362306a36Sopenharmony_ci struct urb **urbs; 20462306a36Sopenharmony_ci int i, r; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci r = -ENOMEM; 20762306a36Sopenharmony_ci urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL); 20862306a36Sopenharmony_ci if (!urbs) 20962306a36Sopenharmony_ci goto error; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci for (i = 0; i < RX_URBS_COUNT; i++) { 21262306a36Sopenharmony_ci urbs[i] = alloc_rx_urb(usb); 21362306a36Sopenharmony_ci if (!urbs[i]) 21462306a36Sopenharmony_ci goto error; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci spin_lock_irq(&rx->lock); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci dev_dbg(plfxlc_usb_dev(usb), "irq_disabled %d\n", irqs_disabled()); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (rx->urbs) { 22262306a36Sopenharmony_ci spin_unlock_irq(&rx->lock); 22362306a36Sopenharmony_ci r = 0; 22462306a36Sopenharmony_ci goto error; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci rx->urbs = urbs; 22762306a36Sopenharmony_ci rx->urbs_count = RX_URBS_COUNT; 22862306a36Sopenharmony_ci spin_unlock_irq(&rx->lock); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci for (i = 0; i < RX_URBS_COUNT; i++) { 23162306a36Sopenharmony_ci r = usb_submit_urb(urbs[i], GFP_KERNEL); 23262306a36Sopenharmony_ci if (r) 23362306a36Sopenharmony_ci goto error_submit; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cierror_submit: 23962306a36Sopenharmony_ci for (i = 0; i < RX_URBS_COUNT; i++) 24062306a36Sopenharmony_ci usb_kill_urb(urbs[i]); 24162306a36Sopenharmony_ci spin_lock_irq(&rx->lock); 24262306a36Sopenharmony_ci rx->urbs = NULL; 24362306a36Sopenharmony_ci rx->urbs_count = 0; 24462306a36Sopenharmony_ci spin_unlock_irq(&rx->lock); 24562306a36Sopenharmony_cierror: 24662306a36Sopenharmony_ci if (urbs) { 24762306a36Sopenharmony_ci for (i = 0; i < RX_URBS_COUNT; i++) 24862306a36Sopenharmony_ci free_rx_urb(urbs[i]); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci kfree(urbs); 25162306a36Sopenharmony_ci return r; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ciint plfxlc_usb_enable_rx(struct plfxlc_usb *usb) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct plfxlc_usb_rx *rx = &usb->rx; 25762306a36Sopenharmony_ci int r; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci mutex_lock(&rx->setup_mutex); 26062306a36Sopenharmony_ci r = __lf_x_usb_enable_rx(usb); 26162306a36Sopenharmony_ci if (!r) 26262306a36Sopenharmony_ci usb->rx_usb_enabled = 1; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci mutex_unlock(&rx->setup_mutex); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return r; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic void __lf_x_usb_disable_rx(struct plfxlc_usb *usb) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct plfxlc_usb_rx *rx = &usb->rx; 27262306a36Sopenharmony_ci unsigned long flags; 27362306a36Sopenharmony_ci unsigned int count; 27462306a36Sopenharmony_ci struct urb **urbs; 27562306a36Sopenharmony_ci int i; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci spin_lock_irqsave(&rx->lock, flags); 27862306a36Sopenharmony_ci urbs = rx->urbs; 27962306a36Sopenharmony_ci count = rx->urbs_count; 28062306a36Sopenharmony_ci spin_unlock_irqrestore(&rx->lock, flags); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (!urbs) 28362306a36Sopenharmony_ci return; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci for (i = 0; i < count; i++) { 28662306a36Sopenharmony_ci usb_kill_urb(urbs[i]); 28762306a36Sopenharmony_ci free_rx_urb(urbs[i]); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci kfree(urbs); 29062306a36Sopenharmony_ci rx->urbs = NULL; 29162306a36Sopenharmony_ci rx->urbs_count = 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_civoid plfxlc_usb_disable_rx(struct plfxlc_usb *usb) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct plfxlc_usb_rx *rx = &usb->rx; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci mutex_lock(&rx->setup_mutex); 29962306a36Sopenharmony_ci __lf_x_usb_disable_rx(usb); 30062306a36Sopenharmony_ci usb->rx_usb_enabled = 0; 30162306a36Sopenharmony_ci mutex_unlock(&rx->setup_mutex); 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_civoid plfxlc_usb_disable_tx(struct plfxlc_usb *usb) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct plfxlc_usb_tx *tx = &usb->tx; 30762306a36Sopenharmony_ci unsigned long flags; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci clear_bit(PLF_BIT_ENABLED, &tx->enabled); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* kill all submitted tx-urbs */ 31262306a36Sopenharmony_ci usb_kill_anchored_urbs(&tx->submitted); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spin_lock_irqsave(&tx->lock, flags); 31562306a36Sopenharmony_ci WARN_ON(!skb_queue_empty(&tx->submitted_skbs)); 31662306a36Sopenharmony_ci WARN_ON(tx->submitted_urbs != 0); 31762306a36Sopenharmony_ci tx->submitted_urbs = 0; 31862306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->lock, flags); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* The stopped state is ignored, relying on ieee80211_wake_queues() 32162306a36Sopenharmony_ci * in a potentionally following plfxlc_usb_enable_tx(). 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_civoid plfxlc_usb_enable_tx(struct plfxlc_usb *usb) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct plfxlc_usb_tx *tx = &usb->tx; 32862306a36Sopenharmony_ci unsigned long flags; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci spin_lock_irqsave(&tx->lock, flags); 33162306a36Sopenharmony_ci set_bit(PLF_BIT_ENABLED, &tx->enabled); 33262306a36Sopenharmony_ci tx->submitted_urbs = 0; 33362306a36Sopenharmony_ci ieee80211_wake_queues(plfxlc_usb_to_hw(usb)); 33462306a36Sopenharmony_ci tx->stopped = 0; 33562306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->lock, flags); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_civoid plfxlc_tx_urb_complete(struct urb *urb) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct ieee80211_tx_info *info; 34162306a36Sopenharmony_ci struct plfxlc_usb *usb; 34262306a36Sopenharmony_ci struct sk_buff *skb; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci skb = urb->context; 34562306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 34662306a36Sopenharmony_ci /* grab 'usb' pointer before handing off the skb (since 34762306a36Sopenharmony_ci * it might be freed by plfxlc_mac_tx_to_dev or mac80211) 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci usb = &plfxlc_hw_mac(info->rate_driver_data[0])->chip.usb; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci switch (urb->status) { 35262306a36Sopenharmony_ci case 0: 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci case -ESHUTDOWN: 35562306a36Sopenharmony_ci case -EINVAL: 35662306a36Sopenharmony_ci case -ENODEV: 35762306a36Sopenharmony_ci case -ENOENT: 35862306a36Sopenharmony_ci case -ECONNRESET: 35962306a36Sopenharmony_ci case -EPIPE: 36062306a36Sopenharmony_ci dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status); 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci default: 36362306a36Sopenharmony_ci dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status); 36462306a36Sopenharmony_ci return; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci plfxlc_mac_tx_to_dev(skb, urb->status); 36862306a36Sopenharmony_ci plfxlc_send_packet_from_data_queue(usb); 36962306a36Sopenharmony_ci usb_free_urb(urb); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic inline void init_usb_rx(struct plfxlc_usb *usb) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct plfxlc_usb_rx *rx = &usb->rx; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci spin_lock_init(&rx->lock); 37762306a36Sopenharmony_ci mutex_init(&rx->setup_mutex); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) 38062306a36Sopenharmony_ci rx->usb_packet_size = 512; 38162306a36Sopenharmony_ci else 38262306a36Sopenharmony_ci rx->usb_packet_size = 64; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (rx->fragment_length != 0) 38562306a36Sopenharmony_ci dev_dbg(plfxlc_usb_dev(usb), "fragment_length error\n"); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic inline void init_usb_tx(struct plfxlc_usb *usb) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct plfxlc_usb_tx *tx = &usb->tx; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci spin_lock_init(&tx->lock); 39362306a36Sopenharmony_ci clear_bit(PLF_BIT_ENABLED, &tx->enabled); 39462306a36Sopenharmony_ci tx->stopped = 0; 39562306a36Sopenharmony_ci skb_queue_head_init(&tx->submitted_skbs); 39662306a36Sopenharmony_ci init_usb_anchor(&tx->submitted); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_civoid plfxlc_usb_init(struct plfxlc_usb *usb, struct ieee80211_hw *hw, 40062306a36Sopenharmony_ci struct usb_interface *intf) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci memset(usb, 0, sizeof(*usb)); 40362306a36Sopenharmony_ci usb->intf = usb_get_intf(intf); 40462306a36Sopenharmony_ci usb_set_intfdata(usb->intf, hw); 40562306a36Sopenharmony_ci init_usb_tx(usb); 40662306a36Sopenharmony_ci init_usb_rx(usb); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_civoid plfxlc_usb_release(struct plfxlc_usb *usb) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci plfxlc_op_stop(plfxlc_usb_to_hw(usb)); 41262306a36Sopenharmony_ci plfxlc_usb_disable_tx(usb); 41362306a36Sopenharmony_ci plfxlc_usb_disable_rx(usb); 41462306a36Sopenharmony_ci usb_set_intfdata(usb->intf, NULL); 41562306a36Sopenharmony_ci usb_put_intf(usb->intf); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ciconst char *plfxlc_speed(enum usb_device_speed speed) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci switch (speed) { 42162306a36Sopenharmony_ci case USB_SPEED_LOW: 42262306a36Sopenharmony_ci return "low"; 42362306a36Sopenharmony_ci case USB_SPEED_FULL: 42462306a36Sopenharmony_ci return "full"; 42562306a36Sopenharmony_ci case USB_SPEED_HIGH: 42662306a36Sopenharmony_ci return "high"; 42762306a36Sopenharmony_ci default: 42862306a36Sopenharmony_ci return "unknown"; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ciint plfxlc_usb_init_hw(struct plfxlc_usb *usb) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci int r; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci r = usb_reset_configuration(plfxlc_usb_to_usbdev(usb)); 43762306a36Sopenharmony_ci if (r) { 43862306a36Sopenharmony_ci dev_err(plfxlc_usb_dev(usb), "cfg reset failed (%d)\n", r); 43962306a36Sopenharmony_ci return r; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic void get_usb_req(struct usb_device *udev, void *buffer, 44562306a36Sopenharmony_ci u32 buffer_len, enum plf_usb_req_enum usb_req_id, 44662306a36Sopenharmony_ci struct plf_usb_req *usb_req) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci __be32 payload_len_nw = cpu_to_be32(buffer_len + FCS_LEN); 44962306a36Sopenharmony_ci const u8 *buffer_src_p = buffer; 45062306a36Sopenharmony_ci u8 *buffer_dst = usb_req->buf; 45162306a36Sopenharmony_ci u32 temp_usb_len = 0; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci usb_req->id = cpu_to_be32(usb_req_id); 45462306a36Sopenharmony_ci usb_req->len = cpu_to_be32(0); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Copy buffer length into the transmitted buffer, as it is important 45762306a36Sopenharmony_ci * for the Rx MAC to know its exact length. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci if (usb_req->id == cpu_to_be32(USB_REQ_BEACON_WR)) { 46062306a36Sopenharmony_ci memcpy(buffer_dst, &payload_len_nw, sizeof(payload_len_nw)); 46162306a36Sopenharmony_ci buffer_dst += sizeof(payload_len_nw); 46262306a36Sopenharmony_ci temp_usb_len += sizeof(payload_len_nw); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci memcpy(buffer_dst, buffer_src_p, buffer_len); 46662306a36Sopenharmony_ci buffer_dst += buffer_len; 46762306a36Sopenharmony_ci buffer_src_p += buffer_len; 46862306a36Sopenharmony_ci temp_usb_len += buffer_len; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Set the FCS_LEN (4) bytes as 0 for CRC checking. */ 47162306a36Sopenharmony_ci memset(buffer_dst, 0, FCS_LEN); 47262306a36Sopenharmony_ci buffer_dst += FCS_LEN; 47362306a36Sopenharmony_ci temp_usb_len += FCS_LEN; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Round the packet to be transmitted to 4 bytes. */ 47662306a36Sopenharmony_ci if (temp_usb_len % PURELIFI_BYTE_NUM_ALIGNMENT) { 47762306a36Sopenharmony_ci memset(buffer_dst, 0, PURELIFI_BYTE_NUM_ALIGNMENT - 47862306a36Sopenharmony_ci (temp_usb_len % 47962306a36Sopenharmony_ci PURELIFI_BYTE_NUM_ALIGNMENT)); 48062306a36Sopenharmony_ci buffer_dst += PURELIFI_BYTE_NUM_ALIGNMENT - 48162306a36Sopenharmony_ci (temp_usb_len % 48262306a36Sopenharmony_ci PURELIFI_BYTE_NUM_ALIGNMENT); 48362306a36Sopenharmony_ci temp_usb_len += PURELIFI_BYTE_NUM_ALIGNMENT - 48462306a36Sopenharmony_ci (temp_usb_len % PURELIFI_BYTE_NUM_ALIGNMENT); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci usb_req->len = cpu_to_be32(temp_usb_len); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ciint plfxlc_usb_wreq_async(struct plfxlc_usb *usb, const u8 *buffer, 49162306a36Sopenharmony_ci int buffer_len, enum plf_usb_req_enum usb_req_id, 49262306a36Sopenharmony_ci usb_complete_t complete_fn, 49362306a36Sopenharmony_ci void *context) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(usb->ez_usb); 49662306a36Sopenharmony_ci struct urb *urb; 49762306a36Sopenharmony_ci int r; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 50062306a36Sopenharmony_ci if (!urb) 50162306a36Sopenharmony_ci return -ENOMEM; 50262306a36Sopenharmony_ci usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), 50362306a36Sopenharmony_ci (void *)buffer, buffer_len, complete_fn, context); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci r = usb_submit_urb(urb, GFP_ATOMIC); 50662306a36Sopenharmony_ci if (r) 50762306a36Sopenharmony_ci dev_err(&udev->dev, "Async write submit failed (%d)\n", r); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci return r; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ciint plfxlc_usb_wreq(struct usb_interface *ez_usb, void *buffer, int buffer_len, 51362306a36Sopenharmony_ci enum plf_usb_req_enum usb_req_id) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(ez_usb); 51662306a36Sopenharmony_ci unsigned char *dma_buffer = NULL; 51762306a36Sopenharmony_ci struct plf_usb_req usb_req; 51862306a36Sopenharmony_ci int usb_bulk_msg_len; 51962306a36Sopenharmony_ci int actual_length; 52062306a36Sopenharmony_ci int r; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci get_usb_req(udev, buffer, buffer_len, usb_req_id, &usb_req); 52362306a36Sopenharmony_ci usb_bulk_msg_len = sizeof(__le32) + sizeof(__le32) + 52462306a36Sopenharmony_ci be32_to_cpu(usb_req.len); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci dma_buffer = kmemdup(&usb_req, usb_bulk_msg_len, GFP_KERNEL); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (!dma_buffer) { 52962306a36Sopenharmony_ci r = -ENOMEM; 53062306a36Sopenharmony_ci goto error; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci r = usb_bulk_msg(udev, 53462306a36Sopenharmony_ci usb_sndbulkpipe(udev, EP_DATA_OUT), 53562306a36Sopenharmony_ci dma_buffer, usb_bulk_msg_len, 53662306a36Sopenharmony_ci &actual_length, USB_BULK_MSG_TIMEOUT_MS); 53762306a36Sopenharmony_ci kfree(dma_buffer); 53862306a36Sopenharmony_cierror: 53962306a36Sopenharmony_ci if (r) { 54062306a36Sopenharmony_ci r = -ENOMEM; 54162306a36Sopenharmony_ci dev_err(&udev->dev, "usb_bulk_msg failed (%d)\n", r); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return r; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic void slif_data_plane_sap_timer_callb(struct timer_list *t) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct plfxlc_usb *usb = from_timer(usb, t, tx.tx_retry_timer); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci plfxlc_send_packet_from_data_queue(usb); 55262306a36Sopenharmony_ci timer_setup(&usb->tx.tx_retry_timer, 55362306a36Sopenharmony_ci slif_data_plane_sap_timer_callb, 0); 55462306a36Sopenharmony_ci mod_timer(&usb->tx.tx_retry_timer, jiffies + TX_RETRY_BACKOFF_JIFF); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic void sta_queue_cleanup_timer_callb(struct timer_list *t) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct plfxlc_usb *usb = from_timer(usb, t, sta_queue_cleanup); 56062306a36Sopenharmony_ci struct plfxlc_usb_tx *tx = &usb->tx; 56162306a36Sopenharmony_ci int sidx; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci for (sidx = 0; sidx < MAX_STA_NUM - 1; sidx++) { 56462306a36Sopenharmony_ci if (!(tx->station[sidx].flag & STATION_CONNECTED_FLAG)) 56562306a36Sopenharmony_ci continue; 56662306a36Sopenharmony_ci if (tx->station[sidx].flag & STATION_HEARTBEAT_FLAG) { 56762306a36Sopenharmony_ci tx->station[sidx].flag ^= STATION_HEARTBEAT_FLAG; 56862306a36Sopenharmony_ci } else { 56962306a36Sopenharmony_ci eth_zero_addr(tx->station[sidx].mac); 57062306a36Sopenharmony_ci tx->station[sidx].flag = 0; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci timer_setup(&usb->sta_queue_cleanup, 57462306a36Sopenharmony_ci sta_queue_cleanup_timer_callb, 0); 57562306a36Sopenharmony_ci mod_timer(&usb->sta_queue_cleanup, jiffies + STA_QUEUE_CLEANUP_JIFF); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int probe(struct usb_interface *intf, 57962306a36Sopenharmony_ci const struct usb_device_id *id) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci u8 serial_number[PURELIFI_SERIAL_LEN]; 58262306a36Sopenharmony_ci struct ieee80211_hw *hw = NULL; 58362306a36Sopenharmony_ci struct plfxlc_usb_tx *tx; 58462306a36Sopenharmony_ci struct plfxlc_chip *chip; 58562306a36Sopenharmony_ci struct plfxlc_usb *usb; 58662306a36Sopenharmony_ci u8 hw_address[ETH_ALEN]; 58762306a36Sopenharmony_ci unsigned int i; 58862306a36Sopenharmony_ci int r = 0; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci hw = plfxlc_mac_alloc_hw(intf); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (!hw) { 59362306a36Sopenharmony_ci r = -ENOMEM; 59462306a36Sopenharmony_ci goto error; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci chip = &plfxlc_hw_mac(hw)->chip; 59862306a36Sopenharmony_ci usb = &chip->usb; 59962306a36Sopenharmony_ci usb->ez_usb = intf; 60062306a36Sopenharmony_ci tx = &usb->tx; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci r = plfxlc_upload_mac_and_serial(intf, hw_address, serial_number); 60362306a36Sopenharmony_ci if (r) { 60462306a36Sopenharmony_ci dev_err(&intf->dev, "MAC and Serial upload failed (%d)\n", r); 60562306a36Sopenharmony_ci goto error; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci chip->unit_type = STA; 60962306a36Sopenharmony_ci dev_err(&intf->dev, "Unit type is station"); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci r = plfxlc_mac_preinit_hw(hw, hw_address); 61262306a36Sopenharmony_ci if (r) { 61362306a36Sopenharmony_ci dev_err(&intf->dev, "Init mac failed (%d)\n", r); 61462306a36Sopenharmony_ci goto error; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci r = ieee80211_register_hw(hw); 61862306a36Sopenharmony_ci if (r) { 61962306a36Sopenharmony_ci dev_err(&intf->dev, "Register device failed (%d)\n", r); 62062306a36Sopenharmony_ci goto error; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if ((le16_to_cpu(interface_to_usbdev(intf)->descriptor.idVendor) == 62462306a36Sopenharmony_ci PURELIFI_XL_VENDOR_ID_0) && 62562306a36Sopenharmony_ci (le16_to_cpu(interface_to_usbdev(intf)->descriptor.idProduct) == 62662306a36Sopenharmony_ci PURELIFI_XL_PRODUCT_ID_0)) { 62762306a36Sopenharmony_ci r = plfxlc_download_xl_firmware(intf); 62862306a36Sopenharmony_ci } else { 62962306a36Sopenharmony_ci r = plfxlc_download_fpga(intf); 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci if (r != 0) { 63262306a36Sopenharmony_ci dev_err(&intf->dev, "FPGA download failed (%d)\n", r); 63362306a36Sopenharmony_ci goto error; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci tx->mac_fifo_full = 0; 63762306a36Sopenharmony_ci spin_lock_init(&tx->lock); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci msleep(PLF_MSLEEP_TIME); 64062306a36Sopenharmony_ci r = plfxlc_usb_init_hw(usb); 64162306a36Sopenharmony_ci if (r < 0) { 64262306a36Sopenharmony_ci dev_err(&intf->dev, "usb_init_hw failed (%d)\n", r); 64362306a36Sopenharmony_ci goto error; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci msleep(PLF_MSLEEP_TIME); 64762306a36Sopenharmony_ci r = plfxlc_chip_switch_radio(chip, PLFXLC_RADIO_ON); 64862306a36Sopenharmony_ci if (r < 0) { 64962306a36Sopenharmony_ci dev_dbg(&intf->dev, "chip_switch_radio_on failed (%d)\n", r); 65062306a36Sopenharmony_ci goto error; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci msleep(PLF_MSLEEP_TIME); 65462306a36Sopenharmony_ci r = plfxlc_chip_set_rate(chip, 8); 65562306a36Sopenharmony_ci if (r < 0) { 65662306a36Sopenharmony_ci dev_dbg(&intf->dev, "chip_set_rate failed (%d)\n", r); 65762306a36Sopenharmony_ci goto error; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci msleep(PLF_MSLEEP_TIME); 66162306a36Sopenharmony_ci r = plfxlc_usb_wreq(usb->ez_usb, 66262306a36Sopenharmony_ci hw_address, ETH_ALEN, USB_REQ_MAC_WR); 66362306a36Sopenharmony_ci if (r < 0) { 66462306a36Sopenharmony_ci dev_dbg(&intf->dev, "MAC_WR failure (%d)\n", r); 66562306a36Sopenharmony_ci goto error; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci plfxlc_chip_enable_rxtx(chip); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* Initialise the data plane Tx queue */ 67162306a36Sopenharmony_ci for (i = 0; i < MAX_STA_NUM; i++) { 67262306a36Sopenharmony_ci skb_queue_head_init(&tx->station[i].data_list); 67362306a36Sopenharmony_ci tx->station[i].flag = 0; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci tx->station[STA_BROADCAST_INDEX].flag |= STATION_CONNECTED_FLAG; 67762306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 67862306a36Sopenharmony_ci tx->station[STA_BROADCAST_INDEX].mac[i] = 0xFF; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci timer_setup(&tx->tx_retry_timer, slif_data_plane_sap_timer_callb, 0); 68162306a36Sopenharmony_ci tx->tx_retry_timer.expires = jiffies + TX_RETRY_BACKOFF_JIFF; 68262306a36Sopenharmony_ci add_timer(&tx->tx_retry_timer); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci timer_setup(&usb->sta_queue_cleanup, 68562306a36Sopenharmony_ci sta_queue_cleanup_timer_callb, 0); 68662306a36Sopenharmony_ci usb->sta_queue_cleanup.expires = jiffies + STA_QUEUE_CLEANUP_JIFF; 68762306a36Sopenharmony_ci add_timer(&usb->sta_queue_cleanup); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci plfxlc_mac_init_hw(hw); 69062306a36Sopenharmony_ci usb->initialized = true; 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_cierror: 69362306a36Sopenharmony_ci if (hw) { 69462306a36Sopenharmony_ci plfxlc_mac_release(plfxlc_hw_mac(hw)); 69562306a36Sopenharmony_ci ieee80211_unregister_hw(hw); 69662306a36Sopenharmony_ci ieee80211_free_hw(hw); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci dev_err(&intf->dev, "pureLifi:Device error"); 69962306a36Sopenharmony_ci return r; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic void disconnect(struct usb_interface *intf) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct ieee80211_hw *hw = plfxlc_intf_to_hw(intf); 70562306a36Sopenharmony_ci struct plfxlc_mac *mac; 70662306a36Sopenharmony_ci struct plfxlc_usb *usb; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* Either something really bad happened, or 70962306a36Sopenharmony_ci * we're just dealing with a DEVICE_INSTALLER. 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_ci if (!hw) 71262306a36Sopenharmony_ci return; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci mac = plfxlc_hw_mac(hw); 71562306a36Sopenharmony_ci usb = &mac->chip.usb; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci del_timer_sync(&usb->tx.tx_retry_timer); 71862306a36Sopenharmony_ci del_timer_sync(&usb->sta_queue_cleanup); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci ieee80211_unregister_hw(hw); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci plfxlc_chip_disable_rxtx(&mac->chip); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* If the disconnect has been caused by a removal of the 72562306a36Sopenharmony_ci * driver module, the reset allows reloading of the driver. If the 72662306a36Sopenharmony_ci * reset will not be executed here, the upload of the firmware in the 72762306a36Sopenharmony_ci * probe function caused by the reloading of the driver will fail. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ci usb_reset_device(interface_to_usbdev(intf)); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci plfxlc_mac_release(mac); 73262306a36Sopenharmony_ci ieee80211_free_hw(hw); 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic void plfxlc_usb_resume(struct plfxlc_usb *usb) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci struct plfxlc_mac *mac = plfxlc_usb_to_mac(usb); 73862306a36Sopenharmony_ci int r; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci r = plfxlc_op_start(plfxlc_usb_to_hw(usb)); 74162306a36Sopenharmony_ci if (r < 0) { 74262306a36Sopenharmony_ci dev_warn(plfxlc_usb_dev(usb), 74362306a36Sopenharmony_ci "Device resume failed (%d)\n", r); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (usb->was_running) 74662306a36Sopenharmony_ci set_bit(PURELIFI_DEVICE_RUNNING, &mac->flags); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci usb_queue_reset_device(usb->intf); 74962306a36Sopenharmony_ci return; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (mac->type != NL80211_IFTYPE_UNSPECIFIED) { 75362306a36Sopenharmony_ci r = plfxlc_restore_settings(mac); 75462306a36Sopenharmony_ci if (r < 0) { 75562306a36Sopenharmony_ci dev_dbg(plfxlc_usb_dev(usb), 75662306a36Sopenharmony_ci "Restore failed (%d)\n", r); 75762306a36Sopenharmony_ci return; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic void plfxlc_usb_stop(struct plfxlc_usb *usb) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci plfxlc_op_stop(plfxlc_usb_to_hw(usb)); 76562306a36Sopenharmony_ci plfxlc_usb_disable_tx(usb); 76662306a36Sopenharmony_ci plfxlc_usb_disable_rx(usb); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci usb->initialized = false; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic int pre_reset(struct usb_interface *intf) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct ieee80211_hw *hw = usb_get_intfdata(intf); 77462306a36Sopenharmony_ci struct plfxlc_mac *mac; 77562306a36Sopenharmony_ci struct plfxlc_usb *usb; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (!hw || intf->condition != USB_INTERFACE_BOUND) 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci mac = plfxlc_hw_mac(hw); 78162306a36Sopenharmony_ci usb = &mac->chip.usb; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci usb->was_running = test_bit(PURELIFI_DEVICE_RUNNING, &mac->flags); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci plfxlc_usb_stop(usb); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci return 0; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic int post_reset(struct usb_interface *intf) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct ieee80211_hw *hw = usb_get_intfdata(intf); 79362306a36Sopenharmony_ci struct plfxlc_mac *mac; 79462306a36Sopenharmony_ci struct plfxlc_usb *usb; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (!hw || intf->condition != USB_INTERFACE_BOUND) 79762306a36Sopenharmony_ci return 0; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci mac = plfxlc_hw_mac(hw); 80062306a36Sopenharmony_ci usb = &mac->chip.usb; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (usb->was_running) 80362306a36Sopenharmony_ci plfxlc_usb_resume(usb); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci#ifdef CONFIG_PM 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_cistatic struct plfxlc_usb *get_plfxlc_usb(struct usb_interface *intf) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct ieee80211_hw *hw = plfxlc_intf_to_hw(intf); 81362306a36Sopenharmony_ci struct plfxlc_mac *mac; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* Either something really bad happened, or 81662306a36Sopenharmony_ci * we're just dealing with a DEVICE_INSTALLER. 81762306a36Sopenharmony_ci */ 81862306a36Sopenharmony_ci if (!hw) 81962306a36Sopenharmony_ci return NULL; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci mac = plfxlc_hw_mac(hw); 82262306a36Sopenharmony_ci return &mac->chip.usb; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic int suspend(struct usb_interface *interface, 82662306a36Sopenharmony_ci pm_message_t message) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct plfxlc_usb *pl = get_plfxlc_usb(interface); 82962306a36Sopenharmony_ci struct plfxlc_mac *mac = plfxlc_usb_to_mac(pl); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (!pl) 83262306a36Sopenharmony_ci return -ENODEV; 83362306a36Sopenharmony_ci if (pl->initialized == 0) 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci pl->was_running = test_bit(PURELIFI_DEVICE_RUNNING, &mac->flags); 83662306a36Sopenharmony_ci plfxlc_usb_stop(pl); 83762306a36Sopenharmony_ci return 0; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic int resume(struct usb_interface *interface) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci struct plfxlc_usb *pl = get_plfxlc_usb(interface); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (!pl) 84562306a36Sopenharmony_ci return -ENODEV; 84662306a36Sopenharmony_ci if (pl->was_running) 84762306a36Sopenharmony_ci plfxlc_usb_resume(pl); 84862306a36Sopenharmony_ci return 0; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci#endif 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic struct usb_driver driver = { 85462306a36Sopenharmony_ci .name = KBUILD_MODNAME, 85562306a36Sopenharmony_ci .id_table = usb_ids, 85662306a36Sopenharmony_ci .probe = probe, 85762306a36Sopenharmony_ci .disconnect = disconnect, 85862306a36Sopenharmony_ci .pre_reset = pre_reset, 85962306a36Sopenharmony_ci .post_reset = post_reset, 86062306a36Sopenharmony_ci#ifdef CONFIG_PM 86162306a36Sopenharmony_ci .suspend = suspend, 86262306a36Sopenharmony_ci .resume = resume, 86362306a36Sopenharmony_ci#endif 86462306a36Sopenharmony_ci .disable_hub_initiated_lpm = 1, 86562306a36Sopenharmony_ci}; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic int __init usb_init(void) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci int r; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci r = usb_register(&driver); 87262306a36Sopenharmony_ci if (r) { 87362306a36Sopenharmony_ci pr_err("%s usb_register() failed %d\n", driver.name, r); 87462306a36Sopenharmony_ci return r; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci pr_debug("Driver initialized :%s\n", driver.name); 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic void __exit usb_exit(void) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci usb_deregister(&driver); 88462306a36Sopenharmony_ci pr_debug("%s %s\n", driver.name, __func__); 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 88862306a36Sopenharmony_ciMODULE_DESCRIPTION("USB driver for pureLiFi devices"); 88962306a36Sopenharmony_ciMODULE_AUTHOR("pureLiFi"); 89062306a36Sopenharmony_ciMODULE_VERSION("1.0"); 89162306a36Sopenharmony_ciMODULE_FIRMWARE("plfxlc/lifi-x.bin"); 89262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, usb_ids); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cimodule_init(usb_init); 89562306a36Sopenharmony_cimodule_exit(usb_exit); 896