[RFC] [PATCH] usbatm.[ch]: logic changes + error handling
Roman Kagan
rkagan at mail.ru
Fri Apr 15 06:18:11 EDT 2005
OK so here goes another update of my patch to the current CVS, in case
it gets somebody interested.
A few numbers to be proud of :) :
text data bss dec hex filename
10275 500 48 10823 2a47 usbatm.orig/usbatm.ko
8905 468 0 9373 249d usbatm/usbatm.ko
usbatm.h | 81 +-----
usbatm.c | 753 +++++++++++++++++++++++++--------------------------------------
2 files changed, 324 insertions(+), 510 deletions(-)
and that's without sacrificing functionality (rather the opposite: added
extra error handling and support for iso transfers).
Cheers,
Roman.
Index: usbatm.h
===================================================================
RCS file: /home/cvs/usbatm/usbatm.h,v
retrieving revision 1.13
diff -u -p -d -w -r1.13 usbatm.h
--- usbatm.h 14 Apr 2005 10:20:26 -0000 1.13
+++ usbatm.h 15 Apr 2005 09:55:23 -0000
@@ -124,55 +124,24 @@ extern int usbatm_usb_probe(struct usb_i
extern void usbatm_usb_disconnect(struct usb_interface *intf);
-/* usbatm */
-
-#define UDSL_MAX_RCV_URBS 4
-#define UDSL_MAX_SND_URBS 4
-#define UDSL_MAX_RCV_BUFS 8
-#define UDSL_MAX_SND_BUFS 8
-#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */
-#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */
-#define UDSL_DEFAULT_RCV_URBS 2
-#define UDSL_DEFAULT_SND_URBS 2
-#define UDSL_DEFAULT_RCV_BUFS 4
-#define UDSL_DEFAULT_SND_BUFS 4
-#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */
-#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */
-
-
-/* receive */
-
-struct usbatm_receive_buffer {
+struct usbatm_channel {
+ int endpoint; /* usb pipe */
+ unsigned int stride; /* ATM cell size + padding */
+ unsigned int buf_size; /* urb buffer size */
+ spinlock_t lock;
struct list_head list;
- unsigned char *base;
- unsigned int filled_cells;
+ struct tasklet_struct tasklet;
+ struct timer_list delay;
+ struct work_struct clear_halt_work;
+ struct usbatm_data *usbatm;
};
-struct usbatm_receiver {
- struct list_head list;
- struct usbatm_receive_buffer *buffer;
+struct usbatm_transceiver {
struct urb *urb;
- struct usbatm_data *instance;
-};
-
-
-/* send */
-
-struct usbatm_send_buffer {
struct list_head list;
- unsigned char *base;
- unsigned char *free_start;
- unsigned int free_cells;
-};
-
-struct usbatm_sender {
- struct list_head list;
- struct usbatm_send_buffer *buffer;
- struct urb *urb;
- struct usbatm_data *instance;
+ struct usbatm_channel *channel;
};
-
/* main driver data */
struct usbatm_data {
@@ -189,10 +158,6 @@ struct usbatm_data {
struct usb_device *usb_dev;
struct usb_interface *usb_intf;
char description[64];
- int tx_endpoint;
- int rx_endpoint;
- int tx_padding;
- int rx_padding;
/* ATM device */
struct atm_dev *atm_dev;
@@ -212,31 +177,13 @@ struct usbatm_data {
/* ATM device */
struct list_head vcc_list;
- /* receive */
- struct usbatm_receiver receivers[UDSL_MAX_RCV_URBS];
- struct usbatm_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS];
-
- spinlock_t receive_lock;
- struct list_head spare_receivers;
- struct list_head filled_receive_buffers;
-
- struct tasklet_struct receive_tasklet;
- struct list_head spare_receive_buffers;
+ struct usbatm_transceiver *transceivers;
- /* send */
- struct usbatm_sender senders[UDSL_MAX_SND_URBS];
- struct usbatm_send_buffer send_buffers[UDSL_MAX_SND_BUFS];
+ struct usbatm_channel rx_channel;
+ struct usbatm_channel tx_channel;
struct sk_buff_head sndqueue;
-
- spinlock_t send_lock;
- struct list_head spare_senders;
- struct list_head spare_send_buffers;
-
- struct tasklet_struct send_tasklet;
struct sk_buff *current_skb; /* being emptied */
- struct usbatm_send_buffer *current_buffer; /* being filled */
- struct list_head filled_send_buffers;
};
#endif /* _USBATM_H_ */
Index: usbatm.c
===================================================================
RCS file: /home/cvs/usbatm/usbatm.c,v
retrieving revision 1.19
diff -u -p -d -w -r1.19 usbatm.c
--- usbatm.c 15 Apr 2005 08:49:51 -0000 1.19
+++ usbatm.c 15 Apr 2005 09:55:23 -0000
@@ -96,22 +96,18 @@ static int usbatm_print_packet(const uns
static const char usbatm_driver_name[] = "usbatm";
-#define UDSL_MAX_RCV_URBS 4
-#define UDSL_MAX_SND_URBS 4
-#define UDSL_MAX_RCV_BUFS 8
-#define UDSL_MAX_SND_BUFS 8
+#define UDSL_MAX_RCV_URBS 16
+#define UDSL_MAX_SND_URBS 16
#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */
#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */
-#define UDSL_DEFAULT_RCV_URBS 2
-#define UDSL_DEFAULT_SND_URBS 2
-#define UDSL_DEFAULT_RCV_BUFS 4
-#define UDSL_DEFAULT_SND_BUFS 4
+#define UDSL_DEFAULT_RCV_URBS 4
+#define UDSL_DEFAULT_SND_URBS 4
#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */
#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
-#define UDSL_NUM_CELLS(x) (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)
+#define THROTTLE_MSECS 5 /* delay to recover processing after urb submission fails */
/* receive */
@@ -130,11 +126,9 @@ struct usbatm_vcc_data {
/* send */
struct usbatm_control {
- struct atm_skb_data atm_data;
- unsigned int num_cells;
- unsigned int num_entire;
- unsigned int pdu_padding;
- unsigned char aal5_trailer[ATM_AAL5_TRAILER];
+ struct atm_vcc *vcc;
+ u32 len;
+ u32 crc;
};
#define UDSL_SKB(x) ((struct usbatm_control *)(x)->cb)
@@ -142,8 +136,6 @@ struct usbatm_control {
static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
-static unsigned int num_rcv_bufs = UDSL_DEFAULT_RCV_BUFS;
-static unsigned int num_snd_bufs = UDSL_DEFAULT_SND_BUFS;
static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE;
static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE;
@@ -159,27 +151,15 @@ MODULE_PARM_DESC(num_snd_urbs,
__MODULE_STRING(UDSL_MAX_SND_URBS) ", default: "
__MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")");
-module_param(num_rcv_bufs, uint, S_IRUGO);
-MODULE_PARM_DESC(num_rcv_bufs,
- "Number of buffers used for reception (range: 0-"
- __MODULE_STRING(UDSL_MAX_RCV_BUFS) ", default: "
- __MODULE_STRING(UDSL_DEFAULT_RCV_BUFS) ")");
-
-module_param(num_snd_bufs, uint, S_IRUGO);
-MODULE_PARM_DESC(num_snd_bufs,
- "Number of buffers used for transmission (range: 0-"
- __MODULE_STRING(UDSL_MAX_SND_BUFS) ", default: "
- __MODULE_STRING(UDSL_DEFAULT_SND_BUFS) ")");
-
module_param(rcv_buf_size, uint, S_IRUGO);
MODULE_PARM_DESC(rcv_buf_size,
- "Size of the buffers used for reception (range: 0-"
+ "Size of the buffers used for reception in ATM cells (range: 0-"
__MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: "
__MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")");
module_param(snd_buf_size, uint, S_IRUGO);
MODULE_PARM_DESC(snd_buf_size,
- "Size of the buffers used for transmission (range: 0-"
+ "Size of the buffers used for transmission in ATM cells (range: 0-"
__MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
__MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
@@ -206,6 +186,11 @@ static struct atmdev_ops usbatm_atm_devo
/***********
** misc **
***********/
+static inline unsigned int usbatm_pdu_length(unsigned int length)
+{
+ length += ATM_CELL_PAYLOAD - 1 + ATM_AAL5_TRAILER;
+ return length - length % ATM_CELL_PAYLOAD;
+}
static inline void usbatm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
{
@@ -215,6 +200,73 @@ static inline void usbatm_pop(struct atm
dev_kfree_skb(skb);
}
+/* buffer management */
+static inline struct usbatm_transceiver *usbatm_pop_transceiver(struct usbatm_channel *channel)
+{
+ struct usbatm_transceiver *trx;
+
+ spin_lock_irq(&channel->lock);
+ if (list_empty(&channel->list)) {
+ spin_unlock_irq(&channel->lock);
+ return NULL;
+ }
+
+ trx = list_entry(channel->list.next, struct usbatm_transceiver, list);
+ list_del(&trx->list);
+ spin_unlock_irq(&channel->lock);
+
+ return trx;
+}
+
+static inline int usbatm_submit(struct usbatm_transceiver *trx)
+{
+ int ret;
+ struct usbatm_channel *channel = trx->channel;
+
+ vdbg("%s: submitting urb 0x%p, trx 0x%p, size %u",
+ __func__, trx->urb, trx, trx->urb->transfer_buffer_length);
+
+ ret = usb_submit_urb(trx->urb, GFP_ATOMIC);
+ if (ret) {
+ usb_dbg(channel->usbatm, "%s: trx 0x%p urb 0x%p submission failed (%d)!\n",
+ __func__, trx, trx->urb, ret);
+
+ /* consider all errors transient and return the buffer back to the queue */
+ spin_lock_irq(&channel->lock);
+ list_add(&trx->list, &channel->list);
+ spin_unlock_irq(&channel->lock);
+
+ /* make sure the channel doesn't stall */
+ mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
+ }
+
+ return ret;
+}
+
+static void usbatm_complete(struct urb *urb, struct pt_regs *regs)
+{
+ struct usbatm_transceiver *trx = urb->context;
+ struct usbatm_channel *channel = trx->channel;
+ unsigned long flags;
+
+ vdbg("%s: urb 0x%p, status %d, actual_length %d, trx 0x%p",
+ __func__, urb, urb->status, urb->actual_length, trx);
+
+ /* may be in_interrupt() */
+ spin_lock_irqsave(&channel->lock, flags);
+ list_add_tail(&trx->list, &channel->list);
+ spin_unlock_irqrestore(&channel->lock, flags);
+
+ if (unlikely(urb->status)) {
+ /* throttle processing in case of an error */
+ mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
+ if (urb->status == -EPIPE) /* this one may be cleaned up at times */
+ schedule_work(&channel->clear_halt_work);
+ }
+ else
+ tasklet_schedule(&channel->tasklet);
+}
+
/*************
** decode **
*************/
@@ -231,24 +283,21 @@ static inline struct usbatm_vcc_data *us
}
static void usbatm_extract_cells(struct usbatm_data *instance,
- unsigned char *source, unsigned int howmany)
+ unsigned char *source, unsigned int avail_data)
{
struct usbatm_vcc_data *cached_vcc = NULL;
struct atm_vcc *vcc;
struct sk_buff *sarb;
struct usbatm_vcc_data *vcc_data;
- int cached_vci = 0;
- unsigned int i;
- int pti;
- int vci;
- short cached_vpi = 0;
- short vpi;
+ u8 pti;
+ u32 vci, cached_vci = 0;
+ u16 vpi, cached_vpi = 0;
- for (i = 0; i < howmany;
- i++, source += ATM_CELL_SIZE + instance->rx_padding) {
+ for (; avail_data >= instance->rx_channel.stride;
+ avail_data -= instance->rx_channel.stride, source += instance->rx_channel.stride) {
vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4);
vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
- pti = (source[3] & 0x2) != 0;
+ pti = ((source[3] & 0xe) >> 1);
vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
@@ -264,6 +313,7 @@ static void usbatm_extract_cells(struct
}
vcc = vcc_data->vcc;
+
sarb = vcc_data->sarb;
if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
@@ -276,7 +326,7 @@ static void usbatm_extract_cells(struct
memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
__skb_put(sarb, ATM_CELL_PAYLOAD);
- if (pti) {
+ if (pti & 1) {
struct sk_buff *skb;
unsigned int length;
unsigned int pdu_length;
@@ -291,7 +341,7 @@ static void usbatm_extract_cells(struct
goto out;
}
- pdu_length = UDSL_NUM_CELLS(length) * ATM_CELL_PAYLOAD;
+ pdu_length = usbatm_pdu_length(length);
if (sarb->len < pdu_length) {
atm_dbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n",
@@ -344,343 +394,153 @@ static void usbatm_extract_cells(struct
** encode **
*************/
-static inline void usbatm_fill_cell_header(unsigned char *target, struct atm_vcc *vcc)
-{
- target[0] = vcc->vpi >> 4;
- target[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
- target[2] = vcc->vci >> 4;
- target[3] = vcc->vci << 4;
- target[4] = 0xec;
-}
-
-static const unsigned char zeros[ATM_CELL_PAYLOAD];
-
-static void usbatm_groom_skb(struct atm_vcc *vcc, struct sk_buff *skb)
+static unsigned int usbatm_write_cells(struct usbatm_data *instance,
+ struct sk_buff *skb,
+ u8 *target, unsigned int avail_space)
{
struct usbatm_control *ctrl = UDSL_SKB(skb);
- unsigned int zero_padding;
- u32 crc;
-
- ctrl->atm_data.vcc = vcc;
-
- ctrl->num_cells = UDSL_NUM_CELLS(skb->len);
- ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
-
- zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER;
-
- if (ctrl->num_entire + 1 < ctrl->num_cells)
- ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
- else
- ctrl->pdu_padding = zero_padding;
-
- ctrl->aal5_trailer[0] = 0; /* UU = 0 */
- ctrl->aal5_trailer[1] = 0; /* CPI = 0 */
- ctrl->aal5_trailer[2] = skb->len >> 8;
- ctrl->aal5_trailer[3] = skb->len;
+ unsigned int num_written;
- crc = crc32_be(~0, skb->data, skb->len);
- crc = crc32_be(crc, zeros, zero_padding);
- crc = crc32_be(crc, ctrl->aal5_trailer, 4);
- crc = ~crc;
+ /* UDSL_ASSERT(!(avail_space % instance->tx_channel.stride)); */
+ BUG_ON(avail_space % instance->tx_channel.stride);
+ vdbg("%s: skb->len=%d, avail_space=%u",
+ __func__, skb->len, avail_space);
- ctrl->aal5_trailer[4] = crc >> 24;
- ctrl->aal5_trailer[5] = crc >> 16;
- ctrl->aal5_trailer[6] = crc >> 8;
- ctrl->aal5_trailer[7] = crc;
-}
+ for (num_written = 0; num_written < avail_space && ctrl->len;
+ num_written += instance->tx_channel.stride, target += instance->tx_channel.stride) {
+ unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);
+ unsigned int left = ATM_CELL_PAYLOAD - data_len;
+ u8 *ptr = target;
-static unsigned int usbatm_write_cells(struct usbatm_data *instance,
- unsigned int howmany, struct sk_buff *skb,
- unsigned char **target_p)
-{
- struct usbatm_control *ctrl = UDSL_SKB(skb);
- unsigned char *target = *target_p;
- unsigned int nc, ne, i;
+ ptr[0] = ctrl->vcc->vpi >> 4;
+ ptr[1] = (ctrl->vcc->vpi << 4) | (ctrl->vcc->vci >> 12);
+ ptr[2] = ctrl->vcc->vci >> 4;
+ ptr[3] = ctrl->vcc->vci << 4;
+ ptr[4] = 0xec;
+ ptr += ATM_CELL_HEADER;
- vdbg("%s: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u",
- __func__, howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding);
+ memcpy(ptr, skb->data, data_len);
+ ptr += data_len;
+ skb_pull(skb, data_len);
- nc = ctrl->num_cells;
- ne = min(howmany, ctrl->num_entire);
+ if(!left)
+ continue;
- for (i = 0; i < ne; i++) {
- usbatm_fill_cell_header(target, ctrl->atm_data.vcc);
- target += ATM_CELL_HEADER;
- memcpy(target, skb->data, ATM_CELL_PAYLOAD);
- target += ATM_CELL_PAYLOAD;
- if (instance->tx_padding) {
- memset(target, 0, instance->tx_padding);
- target += instance->tx_padding;
- }
- __skb_pull(skb, ATM_CELL_PAYLOAD);
- }
+ memset(ptr, 0, left);
- ctrl->num_entire -= ne;
+ if (left >= ATM_AAL5_TRAILER) { /* trailer will go in this cell */
+ u8 *trailer = target + ATM_CELL_SIZE - ATM_AAL5_TRAILER;
+ /* trailer[0] = 0; UU = 0 */
+ /* trailer[1] = 0; CPI = 0 */
+ trailer[2] = ctrl->len >> 8;
+ trailer[3] = ctrl->len;
- if (!(ctrl->num_cells -= ne) || !(howmany -= ne))
- goto out;
+ ctrl->crc = ~ crc32_be(ctrl->crc, ptr, left - 4);
- usbatm_fill_cell_header(target, ctrl->atm_data.vcc);
- target += ATM_CELL_HEADER;
- memcpy(target, skb->data, skb->len);
- target += skb->len;
- __skb_pull(skb, skb->len);
- memset(target, 0, ctrl->pdu_padding);
- target += ctrl->pdu_padding;
+ trailer[4] = ctrl->crc >> 24;
+ trailer[5] = ctrl->crc >> 16;
+ trailer[6] = ctrl->crc >> 8;
+ trailer[7] = ctrl->crc;
- if (--ctrl->num_cells) {
- if (!--howmany) {
- ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
- goto out;
- }
+ target[3] |= 0x2; /* adjust PTI */
- if (instance->tx_padding) {
- memset(target, 0, instance->tx_padding);
- target += instance->tx_padding;
+ ctrl->len = 0; /* tag this skb finished */
}
- usbatm_fill_cell_header(target, ctrl->atm_data.vcc);
- target += ATM_CELL_HEADER;
- memset(target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
- target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
-
- --ctrl->num_cells;
- UDSL_ASSERT(!ctrl->num_cells);
+ else
+ ctrl->crc = crc32_be(ctrl->crc, ptr, left);
}
- memcpy(target, ctrl->aal5_trailer, ATM_AAL5_TRAILER);
- target += ATM_AAL5_TRAILER;
- /* set pti bit in last cell */
- *(target + 3 - ATM_CELL_SIZE) |= 0x2;
- if (instance->tx_padding) {
- memset(target, 0, instance->tx_padding);
- target += instance->tx_padding;
- }
- out:
- *target_p = target;
- return nc - ctrl->num_cells;
+ return num_written;
}
/**************
** receive **
**************/
-static void usbatm_complete_receive(struct urb *urb, struct pt_regs *regs)
-{
- struct usbatm_receive_buffer *buf;
- struct usbatm_data *instance;
- struct usbatm_receiver *rcv;
- unsigned long flags;
-
- if (!urb || !(rcv = urb->context)) {
- dbg("%s: bad urb!", __func__);
- return;
- }
-
- instance = rcv->instance;
- buf = rcv->buffer;
-
- buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rx_padding);
-
- vdbg("%s: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p",
- __func__, urb, urb->status, urb->actual_length, buf->filled_cells, rcv, buf);
-
- UDSL_ASSERT(buf->filled_cells <= rcv_buf_size);
-
- /* may not be in_interrupt() */
- spin_lock_irqsave(&instance->receive_lock, flags);
- list_add(&rcv->list, &instance->spare_receivers);
- list_add_tail(&buf->list, &instance->filled_receive_buffers);
- if (likely(!urb->status))
- tasklet_schedule(&instance->receive_tasklet);
- spin_unlock_irqrestore(&instance->receive_lock, flags);
-}
-
-static void usbatm_process_receive(unsigned long data)
+static void usbatm_rx_process(unsigned long data)
{
- struct usbatm_receive_buffer *buf;
struct usbatm_data *instance = (struct usbatm_data *)data;
- struct usbatm_receiver *rcv;
- int err;
-
- made_progress:
- while (!list_empty(&instance->spare_receive_buffers)) {
- spin_lock_irq(&instance->receive_lock);
- if (list_empty(&instance->spare_receivers)) {
- spin_unlock_irq(&instance->receive_lock);
- break;
- }
- rcv = list_entry(instance->spare_receivers.next,
- struct usbatm_receiver, list);
- list_del(&rcv->list);
- spin_unlock_irq(&instance->receive_lock);
-
- buf = list_entry(instance->spare_receive_buffers.next,
- struct usbatm_receive_buffer, list);
- list_del(&buf->list);
-
- rcv->buffer = buf;
+ struct usbatm_transceiver *rx;
- usb_fill_bulk_urb(rcv->urb, instance->usb_dev,
- instance->rx_endpoint,
- buf->base,
- rcv_buf_size * (ATM_CELL_SIZE + instance->rx_padding),
- usbatm_complete_receive, rcv);
+ while ((rx = usbatm_pop_transceiver(&instance->rx_channel))) {
+ struct urb *urb = rx->urb;
- vdbg("%s: sending urb 0x%p, rcv 0x%p, buf 0x%p",
- __func__, rcv->urb, rcv, buf);
+ vdbg("%s: processing rx 0x%p", __func__, rx);
- if ((err = usb_submit_urb(rcv->urb, GFP_ATOMIC)) < 0) {
- atm_dbg(instance, "%s: urb submission failed (%d)!\n", __func__, err);
- list_add(&buf->list, &instance->spare_receive_buffers);
- spin_lock_irq(&instance->receive_lock);
- list_add(&rcv->list, &instance->spare_receivers);
- spin_unlock_irq(&instance->receive_lock);
- break;
- }
+ if (usb_pipeisoc(urb->pipe)) {
+ int i;
+ for (i = 0; i < urb->number_of_packets; i++)
+ if (!urb->iso_frame_desc[i].status)
+ usbatm_extract_cells(instance,
+ (u8 *)urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
}
+ else
+ if (!urb->status)
+ usbatm_extract_cells(instance, urb->transfer_buffer,
+ urb->actual_length);
- spin_lock_irq(&instance->receive_lock);
- if (list_empty(&instance->filled_receive_buffers)) {
- spin_unlock_irq(&instance->receive_lock);
- return; /* done - no more buffers */
+ if (usbatm_submit(rx))
+ return;
}
- buf = list_entry(instance->filled_receive_buffers.next,
- struct usbatm_receive_buffer, list);
- list_del(&buf->list);
- spin_unlock_irq(&instance->receive_lock);
-
- vdbg("%s: processing buf 0x%p", __func__, buf);
- usbatm_extract_cells(instance, buf->base, buf->filled_cells);
- list_add(&buf->list, &instance->spare_receive_buffers);
- goto made_progress;
}
/***********
** send **
***********/
-static void usbatm_complete_send(struct urb *urb, struct pt_regs *regs)
-{
- struct usbatm_data *instance;
- struct usbatm_sender *snd;
- unsigned long flags;
-
- if (!urb || !(snd = urb->context) || !(instance = snd->instance)) {
- dbg("%s: bad urb!", __func__);
- return;
- }
-
- vdbg("%s: urb 0x%p, status %d, snd 0x%p, buf 0x%p",
- __func__, urb, urb->status, snd, snd->buffer);
-
- /* may not be in_interrupt() */
- spin_lock_irqsave(&instance->send_lock, flags);
- list_add(&snd->list, &instance->spare_senders);
- list_add(&snd->buffer->list, &instance->spare_send_buffers);
- tasklet_schedule(&instance->send_tasklet);
- spin_unlock_irqrestore(&instance->send_lock, flags);
-}
-
-static void usbatm_process_send(unsigned long data)
+static void usbatm_tx_process(unsigned long data)
{
- struct usbatm_send_buffer *buf;
struct usbatm_data *instance = (struct usbatm_data *)data;
- struct sk_buff *skb;
- struct usbatm_sender *snd;
- int err;
- unsigned int num_written;
-
- made_progress:
- spin_lock_irq(&instance->send_lock);
- while (!list_empty(&instance->spare_senders)) {
- if (!list_empty(&instance->filled_send_buffers)) {
- buf = list_entry(instance->filled_send_buffers.next,
- struct usbatm_send_buffer, list);
- list_del(&buf->list);
- } else if ((buf = instance->current_buffer)) {
- instance->current_buffer = NULL;
- } else /* all buffers empty */
- break;
-
- snd = list_entry(instance->spare_senders.next,
- struct usbatm_sender, list);
- list_del(&snd->list);
- spin_unlock_irq(&instance->send_lock);
-
- snd->buffer = buf;
- usb_fill_bulk_urb(snd->urb, instance->usb_dev,
- instance->tx_endpoint,
- buf->base,
- (snd_buf_size - buf->free_cells) * (ATM_CELL_SIZE + instance->tx_padding),
- usbatm_complete_send, snd);
+ struct sk_buff *skb = instance->current_skb;
+ struct usbatm_transceiver *tx = NULL;
+ unsigned int num_written = 0;
+ const unsigned int buf_size = instance->tx_channel.buf_size;
+ u8 *buffer = NULL;
- vdbg("%s: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p",
- __func__, snd->urb, snd_buf_size - buf->free_cells, snd, buf);
+ if (!skb)
+ skb = skb_dequeue(&instance->sndqueue);
- if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) {
- atm_dbg(instance, "%s: urb submission failed (%d)!\n", __func__, err);
- spin_lock_irq(&instance->send_lock);
- list_add(&snd->list, &instance->spare_senders);
- spin_unlock_irq(&instance->send_lock);
- list_add(&buf->list, &instance->filled_send_buffers);
- return; /* bail out */
+ while (skb) {
+ if (!tx) {
+ tx = usbatm_pop_transceiver(&instance->tx_channel);
+ if (!tx)
+ break; /* no more senders */
+ buffer = tx->urb->transfer_buffer;
+ num_written = 0;
}
- spin_lock_irq(&instance->send_lock);
- } /* while */
- spin_unlock_irq(&instance->send_lock);
-
- if (!instance->current_skb)
- instance->current_skb = skb_dequeue(&instance->sndqueue);
- if (!instance->current_skb)
- return; /* done - no more skbs */
+ num_written += usbatm_write_cells(instance, skb,
+ buffer + num_written,
+ buf_size - num_written);
- skb = instance->current_skb;
+ vdbg("%s: wrote %u bytes from skb 0x%p to sender 0x%p",
+ __func__, num_written, skb, tx);
- if (!(buf = instance->current_buffer)) {
- spin_lock_irq(&instance->send_lock);
- if (list_empty(&instance->spare_send_buffers)) {
- instance->current_buffer = NULL;
- spin_unlock_irq(&instance->send_lock);
- return; /* done - no more buffers */
- }
- buf = list_entry(instance->spare_send_buffers.next,
- struct usbatm_send_buffer, list);
- list_del(&buf->list);
- spin_unlock_irq(&instance->send_lock);
+ if (!UDSL_SKB(skb)->len) {
+ struct atm_vcc *vcc = UDSL_SKB(skb)->vcc;
- buf->free_start = buf->base;
- buf->free_cells = snd_buf_size;
+ usbatm_pop(vcc, skb);
+ atomic_inc(&vcc->stats->tx);
- instance->current_buffer = buf;
+ skb = skb_dequeue(&instance->sndqueue);
}
- num_written = usbatm_write_cells(instance, buf->free_cells, skb, &buf->free_start);
-
- vdbg("%s: wrote %u cells from skb 0x%p to buffer 0x%p",
- __func__, num_written, skb, buf);
+ if (num_written == buf_size || !skb) {
+ tx->urb->transfer_buffer_length = num_written;
- if (!(buf->free_cells -= num_written)) {
- list_add_tail(&buf->list, &instance->filled_send_buffers);
- instance->current_buffer = NULL;
+ if (usbatm_submit(tx))
+ break;
+ tx = NULL;
}
- vdbg("%s: buffer contains %d cells, %d left",
- __func__, snd_buf_size - buf->free_cells, buf->free_cells);
-
- if (!UDSL_SKB(skb)->num_cells) {
- struct atm_vcc *vcc = UDSL_SKB(skb)->atm_data.vcc;
-
- usbatm_pop(vcc, skb);
- instance->current_skb = NULL;
-
- atomic_inc(&vcc->stats->tx);
}
- goto made_progress;
+ instance->current_skb = skb;
}
-static void usbatm_cancel_send(struct usbatm_data *instance, struct atm_vcc *vcc)
+static void usbatm_cancel_send(struct usbatm_data *instance,
+ struct atm_vcc *vcc)
{
struct sk_buff *skb, *n;
@@ -689,26 +549,27 @@ static void usbatm_cancel_send(struct us
for (skb = instance->sndqueue.next, n = skb->next;
skb != (struct sk_buff *)&instance->sndqueue;
skb = n, n = skb->next)
- if (UDSL_SKB(skb)->atm_data.vcc == vcc) {
+ if (UDSL_SKB(skb)->vcc == vcc) {
atm_dbg(instance, "%s: popping skb 0x%p\n", __func__, skb);
__skb_unlink(skb, &instance->sndqueue);
usbatm_pop(vcc, skb);
}
spin_unlock_irq(&instance->sndqueue.lock);
- tasklet_disable(&instance->send_tasklet);
- if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm_data.vcc == vcc)) {
+ tasklet_disable(&instance->tx_channel.tasklet);
+ if ((skb = instance->current_skb) && (UDSL_SKB(skb)->vcc == vcc)) {
atm_dbg(instance, "%s: popping current skb (0x%p)\n", __func__, skb);
instance->current_skb = NULL;
usbatm_pop(vcc, skb);
}
- tasklet_enable(&instance->send_tasklet);
+ tasklet_enable(&instance->tx_channel.tasklet);
atm_dbg(instance, "%s done\n", __func__);
}
static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
struct usbatm_data *instance = vcc->dev->dev_data;
+ struct usbatm_control *ctrl = UDSL_SKB(skb);
int err;
vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len);
@@ -734,9 +595,13 @@ static int usbatm_atm_send(struct atm_vc
PACKETDEBUG(skb->data, skb->len);
- usbatm_groom_skb(vcc, skb);
+ /* initialize the control block */
+ ctrl->vcc = vcc;
+ ctrl->len = skb->len;
+ ctrl->crc = crc32_be(~0, skb->data, skb->len);
+
skb_queue_tail(&instance->sndqueue, skb);
- tasklet_schedule(&instance->send_tasklet);
+ tasklet_schedule(&instance->tx_channel.tasklet);
return 0;
@@ -756,8 +621,8 @@ static void usbatm_destroy_instance(stru
dbg("%s", __func__);
- tasklet_kill(&instance->receive_tasklet);
- tasklet_kill(&instance->send_tasklet);
+ tasklet_kill(&instance->rx_channel.tasklet);
+ tasklet_kill(&instance->tx_channel.tasklet);
usb_put_dev(instance->usb_dev);
kfree(instance);
}
@@ -839,7 +704,6 @@ static int usbatm_atm_open(struct atm_vc
{
struct usbatm_data *instance = vcc->dev->dev_data;
struct usbatm_vcc_data *new;
- unsigned int max_pdu;
int vci = vcc->vci;
short vpi = vcc->vpi;
@@ -876,9 +740,8 @@ static int usbatm_atm_open(struct atm_vc
new->vpi = vpi;
new->vci = vci;
- /* usbatm_extract_cells requires at least one cell */
- max_pdu = max(1, UDSL_NUM_CELLS(vcc->qos.rxtp.max_sdu)) * ATM_CELL_PAYLOAD;
- if (!(new->sarb = alloc_skb(max_pdu, GFP_KERNEL))) {
+ new->sarb = alloc_skb(usbatm_pdu_length(vcc->qos.rxtp.max_sdu), GFP_KERNEL);
+ if (!new->sarb) {
atm_dbg(instance, "%s: no memory for SAR buffer!\n", __func__);
kfree(new);
up(&instance->serialize);
@@ -887,9 +750,9 @@ static int usbatm_atm_open(struct atm_vc
vcc->dev_data = new;
- tasklet_disable(&instance->receive_tasklet);
+ tasklet_disable(&instance->rx_channel.tasklet);
list_add(&new->list, &instance->vcc_list);
- tasklet_enable(&instance->receive_tasklet);
+ tasklet_enable(&instance->rx_channel.tasklet);
set_bit(ATM_VF_ADDR, &vcc->flags);
set_bit(ATM_VF_PARTIAL, &vcc->flags);
@@ -897,9 +760,7 @@ static int usbatm_atm_open(struct atm_vc
up(&instance->serialize);
- tasklet_schedule(&instance->receive_tasklet);
-
- atm_dbg(instance, "%s: allocated vcc data 0x%p (max_pdu: %u)\n", __func__, new, max_pdu);
+ atm_dbg(instance, "%s: allocated vcc data 0x%p\n", __func__, new);
return 0;
}
@@ -923,9 +784,9 @@ static void usbatm_atm_close(struct atm_
down(&instance->serialize); /* vs self, usbatm_atm_open */
- tasklet_disable(&instance->receive_tasklet);
+ tasklet_disable(&instance->rx_channel.tasklet);
list_del(&vcc_data->list);
- tasklet_enable(&instance->receive_tasklet);
+ tasklet_enable(&instance->rx_channel.tasklet);
kfree_skb(vcc_data->sarb);
vcc_data->sarb = NULL;
@@ -958,7 +819,7 @@ static int usbatm_atm_ioctl(struct atm_d
static int usbatm_atm_init(struct usbatm_data *instance)
{
struct atm_dev *atm_dev;
- int ret;
+ int ret, i;
/* ATM init */
atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL);
@@ -986,6 +847,10 @@ static int usbatm_atm_init(struct usbatm
mb();
atm_dev->dev_data = instance;
+ /* submit all rx URBs */
+ for (i = 0; i < num_rcv_urbs; i++)
+ usbatm_submit(instance->transceivers + i);
+
return 0;
fail:
@@ -1039,6 +904,29 @@ static int usbatm_heavy_init(struct usba
return 0;
}
+static void usbatm_tasklet_schedule(unsigned long data)
+{
+ tasklet_schedule((struct tasklet *) data);
+}
+
+static void usbatm_clear_halt(void *data)
+{
+ struct usbatm_channel *channel = data;
+
+ /* the processing will get restarted after throttling delay */
+ usb_clear_halt(channel->usbatm->usb_dev, channel->endpoint);
+}
+
+static inline void usbatm_init_channel(struct usbatm_channel *channel)
+{
+ spin_lock_init(&channel->lock);
+ INIT_LIST_HEAD(&channel->list);
+ channel->delay.function = usbatm_tasklet_schedule;
+ channel->delay.data = (unsigned long) &channel->tasklet;
+ init_timer(&channel->delay);
+ INIT_WORK(&channel->clear_halt_work, usbatm_clear_halt, channel);
+}
+
int usbatm_usb_probe (struct usb_interface *intf, const struct usb_device_id *id,
struct usbatm_driver *driver)
{
@@ -1071,10 +959,12 @@ int usbatm_usb_probe (struct usb_interfa
instance->usb_dev = usb_dev;
instance->usb_intf = intf;
- instance->tx_endpoint = usb_sndbulkpipe(usb_dev, driver->out);
- instance->rx_endpoint = usb_rcvbulkpipe(usb_dev, driver->in);
- instance->tx_padding = driver->tx_padding;
- instance->rx_padding = driver->rx_padding;
+ instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->in);
+ instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->out);
+ instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding;
+ instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding;
+ instance->rx_channel.buf_size = rcv_buf_size * instance->rx_channel.stride;
+ instance->tx_channel.buf_size = snd_buf_size * instance->tx_channel.stride;
buf = instance->description;
length = sizeof(instance->description);
@@ -1115,74 +1005,70 @@ int usbatm_usb_probe (struct usb_interfa
INIT_LIST_HEAD(&instance->vcc_list);
- spin_lock_init(&instance->receive_lock);
- INIT_LIST_HEAD(&instance->spare_receivers);
- INIT_LIST_HEAD(&instance->filled_receive_buffers);
-
- tasklet_init(&instance->receive_tasklet, usbatm_process_receive, (unsigned long)instance);
- INIT_LIST_HEAD(&instance->spare_receive_buffers);
+ tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance);
+ tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance);
+ usbatm_init_channel(&instance->rx_channel);
+ usbatm_init_channel(&instance->tx_channel);
+ instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance;
skb_queue_head_init(&instance->sndqueue);
- spin_lock_init(&instance->send_lock);
- INIT_LIST_HEAD(&instance->spare_senders);
- INIT_LIST_HEAD(&instance->spare_send_buffers);
-
- tasklet_init(&instance->send_tasklet, usbatm_process_send, (unsigned long)instance);
- INIT_LIST_HEAD(&instance->filled_send_buffers);
-
- /* receive init */
- for (i = 0; i < num_rcv_urbs; i++) {
- struct usbatm_receiver *rcv = &(instance->receivers[i]);
-
- if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
- dev_dbg(dev, "%s: no memory for receive urb %d!\n", __func__, i);
+ instance->transceivers = kmalloc(sizeof(*instance->transceivers) * (num_rcv_urbs + num_snd_urbs),
+ GFP_KERNEL);
+ if (!instance->transceivers) {
+ dev_dbg(dev, "%s: no memory for transceivers!\n", __func__);
goto fail_unbind;
}
- rcv->instance = instance;
-
- list_add(&rcv->list, &instance->spare_receivers);
- }
+ memset(instance->transceivers, 0, sizeof(*instance->transceivers) * (num_rcv_urbs + num_snd_urbs));
- for (i = 0; i < num_rcv_bufs; i++) {
- struct usbatm_receive_buffer *buf = &(instance->receive_buffers[i]);
+ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+ struct usbatm_transceiver *trx = instance->transceivers + i;
+ u8 *buffer;
+ unsigned int iso_packets = 0, iso_size = 0;
+ trx->channel = i < num_rcv_urbs ? &instance->rx_channel : &instance->tx_channel;
- buf->base = kmalloc(rcv_buf_size * (ATM_CELL_SIZE + instance->rx_padding),
- GFP_KERNEL);
- if (!buf->base) {
- dev_dbg(dev, "%s: no memory for receive buffer %d!\n", __func__, i);
+ buffer = kmalloc(trx->channel->buf_size, GFP_KERNEL);
+ if (!buffer) {
+ dev_dbg(dev, "%s: no memory for buffer %d!\n", __func__, i);
goto fail_unbind;
}
+ memset(buffer, 0, trx->channel->buf_size);
- list_add(&buf->list, &instance->spare_receive_buffers);
+ if (usb_pipeisoc(trx->channel->endpoint)) {
+ /* don't expect iso out endpoints */
+ iso_size = usb_maxpacket(instance->usb_dev, trx->channel->endpoint, 0);
+ iso_size -= iso_size % trx->channel->stride; /* alignment */
+ BUG_ON(!iso_size);
+ iso_packets = (trx->channel->buf_size - 1) / iso_size + 1;
}
- /* send init */
- for (i = 0; i < num_snd_urbs; i++) {
- struct usbatm_sender *snd = &(instance->senders[i]);
-
- if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
- dev_dbg(dev, "%s: no memory for send urb %d!\n", __func__, i);
+ trx->urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
+ if (!trx->urb) {
+ dev_dbg(dev, "%s: no memory for urb %d!\n", __func__, i);
goto fail_unbind;
}
- snd->instance = instance;
-
- list_add(&snd->list, &instance->spare_senders);
+ usb_fill_bulk_urb(trx->urb, instance->usb_dev, trx->channel->endpoint,
+ buffer, trx->channel->buf_size, usbatm_complete, trx);
+ if (iso_packets) {
+ int j;
+ trx->urb->interval = 1;
+ trx->urb->transfer_flags = URB_ISO_ASAP;
+ trx->urb->number_of_packets = iso_packets;
+ for (j = 0; j < iso_packets; j++) {
+ trx->urb->iso_frame_desc[j].offset = iso_size * j;
+ trx->urb->iso_frame_desc[j].length = min_t(int, iso_size,
+ trx->channel->buf_size - trx->urb->iso_frame_desc[j].offset);
}
-
- for (i = 0; i < num_snd_bufs; i++) {
- struct usbatm_send_buffer *buf = &(instance->send_buffers[i]);
-
- buf->base = kmalloc(snd_buf_size * (ATM_CELL_SIZE + instance->tx_padding),
- GFP_KERNEL);
- if (!buf->base) {
- dev_dbg(dev, "%s: no memory for send buffer %d!\n", __func__, i);
- goto fail_unbind;
}
- list_add(&buf->list, &instance->spare_send_buffers);
+ /* put all tx URBs on the list of spares */
+ if (i >= num_rcv_urbs)
+ list_add(&trx->list, &trx->channel->list);
+
+ vdbg("%s: alloced trx 0x%p buffer 0x%p buf size %u urb 0x%p",
+ __func__, trx, trx->urb->transfer_buffer, trx->urb->transfer_buffer_length, trx->urb);
}
if (need_heavy && driver->heavy_init) {
@@ -1204,18 +1090,13 @@ int usbatm_usb_probe (struct usb_interfa
if (instance->driver->unbind)
instance->driver->unbind(instance, intf);
fail_free:
- for (i = 0; i < num_snd_bufs; i++)
- kfree(instance->send_buffers[i].base);
-
- for (i = 0; i < num_snd_urbs; i++)
- usb_free_urb(instance->senders[i].urb);
-
- for (i = 0; i < num_rcv_bufs; i++)
- kfree(instance->receive_buffers[i].base);
-
- for (i = 0; i < num_rcv_urbs; i++)
- usb_free_urb(instance->receivers[i].urb);
+ if (instance->transceivers)
+ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+ kfree(instance->transceivers[i].urb->transfer_buffer);
+ usb_free_urb(instance->transceivers[i].urb);
+ }
+ kfree(instance->transceivers);
kfree (instance);
return error;
@@ -1228,7 +1109,7 @@ void usbatm_usb_disconnect(struct usb_in
struct usbatm_data *instance = usb_get_intfdata(intf);
int i;
- dev_dbg(dev, "%s entered\n", __func__);
+ dev_dbg(dev, "%s: disconnect entered\n", __func__);
if (!instance) {
dev_dbg(dev, "%s: NULL instance!\n", __func__);
@@ -1244,51 +1125,39 @@ void usbatm_usb_disconnect(struct usb_in
wait_for_completion(&instance->thread_exited);
- tasklet_disable(&instance->receive_tasklet);
- tasklet_disable(&instance->send_tasklet);
+ tasklet_disable(&instance->rx_channel.tasklet);
+ tasklet_disable(&instance->tx_channel.tasklet);
+
+ del_timer_sync(&instance->rx_channel.delay);
+ del_timer_sync(&instance->tx_channel.delay);
if (instance->atm_dev && instance->driver->atm_stop)
instance->driver->atm_stop(instance, instance->atm_dev);
+ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++)
+ usb_kill_urb(instance->transceivers[i].urb);
+
+ flush_scheduled_work(); /* in case we scheduled clear_halt */
+
if (instance->driver->unbind)
instance->driver->unbind(instance, intf);
instance->driver_data = NULL;
- /* receive finalize */
-
- for (i = 0; i < num_rcv_urbs; i++)
- usb_kill_urb(instance->receivers[i].urb);
-
- /* no need to take the spinlock */
- INIT_LIST_HEAD(&instance->filled_receive_buffers);
- INIT_LIST_HEAD(&instance->spare_receive_buffers);
-
- tasklet_enable(&instance->receive_tasklet);
-
- for (i = 0; i < num_rcv_urbs; i++)
- usb_free_urb(instance->receivers[i].urb);
-
- for (i = 0; i < num_rcv_bufs; i++)
- kfree(instance->receive_buffers[i].base);
-
- /* send finalize */
-
- for (i = 0; i < num_snd_urbs; i++)
- usb_kill_urb(instance->senders[i].urb);
-
+ /* turn usbatm_[rt]x_process into noop */
/* no need to take the spinlock */
- INIT_LIST_HEAD(&instance->spare_senders);
- INIT_LIST_HEAD(&instance->spare_send_buffers);
- instance->current_buffer = NULL;
+ INIT_LIST_HEAD(&instance->rx_channel.list);
+ INIT_LIST_HEAD(&instance->tx_channel.list);
- tasklet_enable(&instance->send_tasklet);
+ tasklet_enable(&instance->rx_channel.tasklet);
+ tasklet_enable(&instance->tx_channel.tasklet);
- for (i = 0; i < num_snd_urbs; i++)
- usb_free_urb(instance->senders[i].urb);
+ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+ kfree(instance->transceivers[i].urb->transfer_buffer);
+ usb_free_urb(instance->transceivers[i].urb);
+ }
- for (i = 0; i < num_snd_bufs; i++)
- kfree(instance->send_buffers[i].base);
+ kfree(instance->transceivers);
/* ATM finalize */
if (instance->atm_dev)
@@ -1314,8 +1183,6 @@ static int __init usbatm_usb_init(void)
if ((num_rcv_urbs > UDSL_MAX_RCV_URBS)
|| (num_snd_urbs > UDSL_MAX_SND_URBS)
- || (num_rcv_bufs > UDSL_MAX_RCV_BUFS)
- || (num_snd_bufs > UDSL_MAX_SND_BUFS)
|| (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE)
|| (snd_buf_size > UDSL_MAX_SND_BUF_SIZE))
return -EINVAL;
More information about the Usbatm
mailing list