5a0e3ad6af
percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
475 lines
15 KiB
C
475 lines
15 KiB
C
/*
|
|
* WUSB Wire Adapter: WLP interface
|
|
* Driver for the Linux Network stack.
|
|
*
|
|
* Copyright (C) 2005-2006 Intel Corporation
|
|
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version
|
|
* 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*
|
|
*
|
|
* i1480u's RX handling is simple. i1480u will send the received
|
|
* network packets broken up in fragments; 1 to N fragments make a
|
|
* packet, we assemble them together and deliver the packet with netif_rx().
|
|
*
|
|
* Beacuse each USB transfer is a *single* fragment (except when the
|
|
* transfer contains a first fragment), each URB called thus
|
|
* back contains one or two fragments. So we queue N URBs, each with its own
|
|
* fragment buffer. When a URB is done, we process it (adding to the
|
|
* current skb from the fragment buffer until complete). Once
|
|
* processed, we requeue the URB. There is always a bunch of URBs
|
|
* ready to take data, so the intergap should be minimal.
|
|
*
|
|
* An URB's transfer buffer is the data field of a socket buffer. This
|
|
* reduces copying as data can be passed directly to network layer. If a
|
|
* complete packet or 1st fragment is received the URB's transfer buffer is
|
|
* taken away from it and used to send data to the network layer. In this
|
|
* case a new transfer buffer is allocated to the URB before being requeued.
|
|
* If a "NEXT" or "LAST" fragment is received, the fragment contents is
|
|
* appended to the RX packet under construction and the transfer buffer
|
|
* is reused. To be able to use this buffer to assemble complete packets
|
|
* we set each buffer's size to that of the MAX ethernet packet that can
|
|
* be received. There is thus room for improvement in memory usage.
|
|
*
|
|
* When the max tx fragment size increases, we should be able to read
|
|
* data into the skbs directly with very simple code.
|
|
*
|
|
* ROADMAP:
|
|
*
|
|
* ENTRY POINTS:
|
|
*
|
|
* i1480u_rx_setup(): setup RX context [from i1480u_open()]
|
|
*
|
|
* i1480u_rx_release(): release RX context [from i1480u_stop()]
|
|
*
|
|
* i1480u_rx_cb(): called when the RX USB URB receives a
|
|
* packet. It removes the header and pushes it up
|
|
* the Linux netdev stack with netif_rx().
|
|
*
|
|
* i1480u_rx_buffer()
|
|
* i1480u_drop() and i1480u_fix()
|
|
* i1480u_skb_deliver
|
|
*
|
|
*/
|
|
|
|
#include <linux/gfp.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/etherdevice.h>
|
|
#include "i1480u-wlp.h"
|
|
|
|
/*
|
|
* Setup the RX context
|
|
*
|
|
* Each URB is provided with a transfer_buffer that is the data field
|
|
* of a new socket buffer.
|
|
*/
|
|
int i1480u_rx_setup(struct i1480u *i1480u)
|
|
{
|
|
int result, cnt;
|
|
struct device *dev = &i1480u->usb_iface->dev;
|
|
struct net_device *net_dev = i1480u->net_dev;
|
|
struct usb_endpoint_descriptor *epd;
|
|
struct sk_buff *skb;
|
|
|
|
/* Alloc RX stuff */
|
|
i1480u->rx_skb = NULL; /* not in process of receiving packet */
|
|
result = -ENOMEM;
|
|
epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc;
|
|
for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
|
|
struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt];
|
|
rx_buf->i1480u = i1480u;
|
|
skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
|
|
if (!skb) {
|
|
dev_err(dev,
|
|
"RX: cannot allocate RX buffer %d\n", cnt);
|
|
result = -ENOMEM;
|
|
goto error;
|
|
}
|
|
skb->dev = net_dev;
|
|
skb->ip_summed = CHECKSUM_NONE;
|
|
skb_reserve(skb, 2);
|
|
rx_buf->data = skb;
|
|
rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
if (unlikely(rx_buf->urb == NULL)) {
|
|
dev_err(dev, "RX: cannot allocate URB %d\n", cnt);
|
|
result = -ENOMEM;
|
|
goto error;
|
|
}
|
|
usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev,
|
|
usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress),
|
|
rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2,
|
|
i1480u_rx_cb, rx_buf);
|
|
result = usb_submit_urb(rx_buf->urb, GFP_NOIO);
|
|
if (unlikely(result < 0)) {
|
|
dev_err(dev, "RX: cannot submit URB %d: %d\n",
|
|
cnt, result);
|
|
goto error;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
error:
|
|
i1480u_rx_release(i1480u);
|
|
return result;
|
|
}
|
|
|
|
|
|
/* Release resources associated to the rx context */
|
|
void i1480u_rx_release(struct i1480u *i1480u)
|
|
{
|
|
int cnt;
|
|
for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
|
|
if (i1480u->rx_buf[cnt].data)
|
|
dev_kfree_skb(i1480u->rx_buf[cnt].data);
|
|
if (i1480u->rx_buf[cnt].urb) {
|
|
usb_kill_urb(i1480u->rx_buf[cnt].urb);
|
|
usb_free_urb(i1480u->rx_buf[cnt].urb);
|
|
}
|
|
}
|
|
if (i1480u->rx_skb != NULL)
|
|
dev_kfree_skb(i1480u->rx_skb);
|
|
}
|
|
|
|
static
|
|
void i1480u_rx_unlink_urbs(struct i1480u *i1480u)
|
|
{
|
|
int cnt;
|
|
for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
|
|
if (i1480u->rx_buf[cnt].urb)
|
|
usb_unlink_urb(i1480u->rx_buf[cnt].urb);
|
|
}
|
|
}
|
|
|
|
/* Fix an out-of-sequence packet */
|
|
#define i1480u_fix(i1480u, msg...) \
|
|
do { \
|
|
if (printk_ratelimit()) \
|
|
dev_err(&i1480u->usb_iface->dev, msg); \
|
|
dev_kfree_skb_irq(i1480u->rx_skb); \
|
|
i1480u->rx_skb = NULL; \
|
|
i1480u->rx_untd_pkt_size = 0; \
|
|
} while (0)
|
|
|
|
|
|
/* Drop an out-of-sequence packet */
|
|
#define i1480u_drop(i1480u, msg...) \
|
|
do { \
|
|
if (printk_ratelimit()) \
|
|
dev_err(&i1480u->usb_iface->dev, msg); \
|
|
i1480u->net_dev->stats.rx_dropped++; \
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
/* Finalizes setting up the SKB and delivers it
|
|
*
|
|
* We first pass the incoming frame to WLP substack for verification. It
|
|
* may also be a WLP association frame in which case WLP will take over the
|
|
* processing. If WLP does not take it over it will still verify it, if the
|
|
* frame is invalid the skb will be freed by WLP and we will not continue
|
|
* parsing.
|
|
* */
|
|
static
|
|
void i1480u_skb_deliver(struct i1480u *i1480u)
|
|
{
|
|
int should_parse;
|
|
struct net_device *net_dev = i1480u->net_dev;
|
|
struct device *dev = &i1480u->usb_iface->dev;
|
|
|
|
should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb,
|
|
&i1480u->rx_srcaddr);
|
|
if (!should_parse)
|
|
goto out;
|
|
i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev);
|
|
net_dev->stats.rx_packets++;
|
|
net_dev->stats.rx_bytes += i1480u->rx_untd_pkt_size;
|
|
|
|
netif_rx(i1480u->rx_skb); /* deliver */
|
|
out:
|
|
i1480u->rx_skb = NULL;
|
|
i1480u->rx_untd_pkt_size = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process a buffer of data received from the USB RX endpoint
|
|
*
|
|
* First fragment arrives with next or last fragment. All other fragments
|
|
* arrive alone.
|
|
*
|
|
* /me hates long functions.
|
|
*/
|
|
static
|
|
void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf)
|
|
{
|
|
unsigned pkt_completed = 0; /* !0 when we got all pkt fragments */
|
|
size_t untd_hdr_size, untd_frg_size;
|
|
size_t i1480u_hdr_size;
|
|
struct wlp_rx_hdr *i1480u_hdr = NULL;
|
|
|
|
struct i1480u *i1480u = rx_buf->i1480u;
|
|
struct sk_buff *skb = rx_buf->data;
|
|
int size_left = rx_buf->urb->actual_length;
|
|
void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */
|
|
struct untd_hdr *untd_hdr;
|
|
|
|
struct net_device *net_dev = i1480u->net_dev;
|
|
struct device *dev = &i1480u->usb_iface->dev;
|
|
struct sk_buff *new_skb;
|
|
|
|
#if 0
|
|
dev_fnstart(dev,
|
|
"(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left);
|
|
dev_err(dev, "RX packet, %zu bytes\n", size_left);
|
|
dump_bytes(dev, ptr, size_left);
|
|
#endif
|
|
i1480u_hdr_size = sizeof(struct wlp_rx_hdr);
|
|
|
|
while (size_left > 0) {
|
|
if (pkt_completed) {
|
|
i1480u_drop(i1480u, "RX: fragment follows completed"
|
|
"packet in same buffer. Dropping\n");
|
|
break;
|
|
}
|
|
untd_hdr = ptr;
|
|
if (size_left < sizeof(*untd_hdr)) { /* Check the UNTD header */
|
|
i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n");
|
|
goto out;
|
|
}
|
|
if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) { /* Paranoia: TX set? */
|
|
i1480u_drop(i1480u, "RX: TX bit set! Dropping\n");
|
|
goto out;
|
|
}
|
|
switch (untd_hdr_type(untd_hdr)) { /* Check the UNTD header type */
|
|
case i1480u_PKT_FRAG_1ST: {
|
|
struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr;
|
|
dev_dbg(dev, "1st fragment\n");
|
|
untd_hdr_size = sizeof(struct untd_hdr_1st);
|
|
if (i1480u->rx_skb != NULL)
|
|
i1480u_fix(i1480u, "RX: 1st fragment out of "
|
|
"sequence! Fixing\n");
|
|
if (size_left < untd_hdr_size + i1480u_hdr_size) {
|
|
i1480u_drop(i1480u, "RX: short 1st fragment! "
|
|
"Dropping\n");
|
|
goto out;
|
|
}
|
|
i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len)
|
|
- i1480u_hdr_size;
|
|
untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len);
|
|
if (size_left < untd_hdr_size + untd_frg_size) {
|
|
i1480u_drop(i1480u,
|
|
"RX: short payload! Dropping\n");
|
|
goto out;
|
|
}
|
|
i1480u->rx_skb = skb;
|
|
i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size;
|
|
i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
|
|
skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size);
|
|
skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
|
|
stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
|
|
stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
|
|
rx_buf->data = NULL; /* need to create new buffer */
|
|
break;
|
|
}
|
|
case i1480u_PKT_FRAG_NXT: {
|
|
dev_dbg(dev, "nxt fragment\n");
|
|
untd_hdr_size = sizeof(struct untd_hdr_rst);
|
|
if (i1480u->rx_skb == NULL) {
|
|
i1480u_drop(i1480u, "RX: next fragment out of "
|
|
"sequence! Dropping\n");
|
|
goto out;
|
|
}
|
|
if (size_left < untd_hdr_size) {
|
|
i1480u_drop(i1480u, "RX: short NXT fragment! "
|
|
"Dropping\n");
|
|
goto out;
|
|
}
|
|
untd_frg_size = le16_to_cpu(untd_hdr->len);
|
|
if (size_left < untd_hdr_size + untd_frg_size) {
|
|
i1480u_drop(i1480u,
|
|
"RX: short payload! Dropping\n");
|
|
goto out;
|
|
}
|
|
memmove(skb_put(i1480u->rx_skb, untd_frg_size),
|
|
ptr + untd_hdr_size, untd_frg_size);
|
|
break;
|
|
}
|
|
case i1480u_PKT_FRAG_LST: {
|
|
dev_dbg(dev, "Lst fragment\n");
|
|
untd_hdr_size = sizeof(struct untd_hdr_rst);
|
|
if (i1480u->rx_skb == NULL) {
|
|
i1480u_drop(i1480u, "RX: last fragment out of "
|
|
"sequence! Dropping\n");
|
|
goto out;
|
|
}
|
|
if (size_left < untd_hdr_size) {
|
|
i1480u_drop(i1480u, "RX: short LST fragment! "
|
|
"Dropping\n");
|
|
goto out;
|
|
}
|
|
untd_frg_size = le16_to_cpu(untd_hdr->len);
|
|
if (size_left < untd_frg_size + untd_hdr_size) {
|
|
i1480u_drop(i1480u,
|
|
"RX: short payload! Dropping\n");
|
|
goto out;
|
|
}
|
|
memmove(skb_put(i1480u->rx_skb, untd_frg_size),
|
|
ptr + untd_hdr_size, untd_frg_size);
|
|
pkt_completed = 1;
|
|
break;
|
|
}
|
|
case i1480u_PKT_FRAG_CMP: {
|
|
dev_dbg(dev, "cmp fragment\n");
|
|
untd_hdr_size = sizeof(struct untd_hdr_cmp);
|
|
if (i1480u->rx_skb != NULL)
|
|
i1480u_fix(i1480u, "RX: fix out-of-sequence CMP"
|
|
" fragment!\n");
|
|
if (size_left < untd_hdr_size + i1480u_hdr_size) {
|
|
i1480u_drop(i1480u, "RX: short CMP fragment! "
|
|
"Dropping\n");
|
|
goto out;
|
|
}
|
|
i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len);
|
|
untd_frg_size = i1480u->rx_untd_pkt_size;
|
|
if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) {
|
|
i1480u_drop(i1480u,
|
|
"RX: short payload! Dropping\n");
|
|
goto out;
|
|
}
|
|
i1480u->rx_skb = skb;
|
|
i1480u_hdr = (void *) untd_hdr + untd_hdr_size;
|
|
i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
|
|
stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
|
|
stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
|
|
skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size);
|
|
skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
|
|
rx_buf->data = NULL; /* for hand off skb to network stack */
|
|
pkt_completed = 1;
|
|
i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */
|
|
break;
|
|
}
|
|
default:
|
|
i1480u_drop(i1480u, "RX: unknown packet type %u! "
|
|
"Dropping\n", untd_hdr_type(untd_hdr));
|
|
goto out;
|
|
}
|
|
size_left -= untd_hdr_size + untd_frg_size;
|
|
if (size_left > 0)
|
|
ptr += untd_hdr_size + untd_frg_size;
|
|
}
|
|
if (pkt_completed)
|
|
i1480u_skb_deliver(i1480u);
|
|
out:
|
|
/* recreate needed RX buffers*/
|
|
if (rx_buf->data == NULL) {
|
|
/* buffer is being used to receive packet, create new */
|
|
new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
|
|
if (!new_skb) {
|
|
if (printk_ratelimit())
|
|
dev_err(dev,
|
|
"RX: cannot allocate RX buffer\n");
|
|
} else {
|
|
new_skb->dev = net_dev;
|
|
new_skb->ip_summed = CHECKSUM_NONE;
|
|
skb_reserve(new_skb, 2);
|
|
rx_buf->data = new_skb;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Called when an RX URB has finished receiving or has found some kind
|
|
* of error condition.
|
|
*
|
|
* LIMITATIONS:
|
|
*
|
|
* - We read USB-transfers, each transfer contains a SINGLE fragment
|
|
* (can contain a complete packet, or a 1st, next, or last fragment
|
|
* of a packet).
|
|
* Looks like a transfer can contain more than one fragment (07/18/06)
|
|
*
|
|
* - Each transfer buffer is the size of the maximum packet size (minus
|
|
* headroom), i1480u_MAX_PKT_SIZE - 2
|
|
*
|
|
* - We always read the full USB-transfer, no partials.
|
|
*
|
|
* - Each transfer is read directly into a skb. This skb will be used to
|
|
* send data to the upper layers if it is the first fragment or a complete
|
|
* packet. In the other cases the data will be copied from the skb to
|
|
* another skb that is being prepared for the upper layers from a prev
|
|
* first fragment.
|
|
*
|
|
* It is simply too much of a pain. Gosh, there should be a unified
|
|
* SG infrastructure for *everything* [so that I could declare a SG
|
|
* buffer, pass it to USB for receiving, append some space to it if
|
|
* I wish, receive more until I have the whole chunk, adapt
|
|
* pointers on each fragment to remove hardware headers and then
|
|
* attach that to an skbuff and netif_rx()].
|
|
*/
|
|
void i1480u_rx_cb(struct urb *urb)
|
|
{
|
|
int result;
|
|
int do_parse_buffer = 1;
|
|
struct i1480u_rx_buf *rx_buf = urb->context;
|
|
struct i1480u *i1480u = rx_buf->i1480u;
|
|
struct device *dev = &i1480u->usb_iface->dev;
|
|
unsigned long flags;
|
|
u8 rx_buf_idx = rx_buf - i1480u->rx_buf;
|
|
|
|
switch (urb->status) {
|
|
case 0:
|
|
break;
|
|
case -ECONNRESET: /* Not an error, but a controlled situation; */
|
|
case -ENOENT: /* (we killed the URB)...so, no broadcast */
|
|
case -ESHUTDOWN: /* going away! */
|
|
dev_err(dev, "RX URB[%u]: goind down %d\n",
|
|
rx_buf_idx, urb->status);
|
|
goto error;
|
|
default:
|
|
dev_err(dev, "RX URB[%u]: unknown status %d\n",
|
|
rx_buf_idx, urb->status);
|
|
if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS,
|
|
EDC_ERROR_TIMEFRAME)) {
|
|
dev_err(dev, "RX: max acceptable errors exceeded,"
|
|
" resetting device.\n");
|
|
i1480u_rx_unlink_urbs(i1480u);
|
|
wlp_reset_all(&i1480u->wlp);
|
|
goto error;
|
|
}
|
|
do_parse_buffer = 0;
|
|
break;
|
|
}
|
|
spin_lock_irqsave(&i1480u->lock, flags);
|
|
/* chew the data fragments, extract network packets */
|
|
if (do_parse_buffer) {
|
|
i1480u_rx_buffer(rx_buf);
|
|
if (rx_buf->data) {
|
|
rx_buf->urb->transfer_buffer = rx_buf->data->data;
|
|
result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC);
|
|
if (result < 0) {
|
|
dev_err(dev, "RX URB[%u]: cannot submit %d\n",
|
|
rx_buf_idx, result);
|
|
}
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&i1480u->lock, flags);
|
|
error:
|
|
return;
|
|
}
|
|
|