Put in infrastructure for the new send code. The only code changes are in the
udsl_usb_probe and udsl_usb_disconnect functions, changed to initialize/finalize the
new fields (plus cleaned up a bit). I couldn't resist a real code change while I was
there: freeing the memory used by the ATM after shutting it down, rather than before!
This doesn't make any difference since the shutdown routine doesn't work - so it still
oopses. I will fix the shutdown routine later.
speedtouch.c | 160 ++++++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 116 insertions(+), 44 deletions(-)
diff -Nru a/drivers/usb/misc/speedtouch.c b/drivers/usb/misc/speedtouch.c
--- a/drivers/usb/misc/speedtouch.c Wed Feb 5 16:20:40 2003
+++ b/drivers/usb/misc/speedtouch.c Wed Feb 5 16:20:40 2003
@@ -90,7 +90,9 @@
#define UDSL_NUMBER_RCV_URBS 1
#define UDSL_NUMBER_SND_URBS 1
+#define UDSL_NUMBER_SND_BUFS (2*UDSL_NUMBER_SND_URBS)
#define UDSL_RCV_BUFFER_SIZE (1*64) /* ATM cells */
+#define UDSL_SND_BUFFER_SIZE (2*64) /* ATM cells */
/* max should be (1500 IP mtu + 2 ppp bytes + 32 * 5 cellheader overhead) for
* PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */
#define UDSL_MAX_AAL5_MRU 2048
@@ -123,10 +125,19 @@
struct udsl_instance_data *instance;
};
+struct udsl_send_buffer {
+ struct list_head list;
+ unsigned char *base;
+ unsigned char *free_start;
+ unsigned int free_cells;
+};
+
struct udsl_usb_send_data_context {
- struct urb *urb;
+ struct list_head list;
+ struct udsl_send_buffer *buffer;
struct sk_buff *skb;
struct atm_vcc *vcc;
+ struct urb *urb;
struct udsl_instance_data *instance;
};
@@ -139,13 +150,10 @@
/* usb device part */
struct usb_device *usb_dev;
- struct sk_buff_head sndqueue;
- struct udsl_usb_send_data_context send_ctx [UDSL_NUMBER_SND_URBS];
int firmware_loaded;
/* atm device part */
struct atm_dev *atm_dev;
-
struct atmsar_vcc_data *atmsar_vcc_list;
/* receiving */
@@ -158,6 +166,21 @@
struct list_head completed_receivers;
struct tasklet_struct receive_tasklet;
+
+ /* sending */
+ struct udsl_usb_send_data_context send_ctx [UDSL_NUMBER_SND_URBS];
+ struct udsl_send_buffer all_buffers [UDSL_NUMBER_SND_BUFS];
+
+ struct sk_buff_head sndqueue;
+
+ spinlock_t send_lock;
+ struct list_head spare_senders;
+ struct list_head spare_buffers;
+
+ struct tasklet_struct send_tasklet;
+ struct sk_buff *current_skb;
+ struct udsl_send_buffer *current_buffer;
+ struct list_head filled_buffers;
};
static const char udsl_driver_name [] = "Alcatel SpeedTouch USB";
@@ -371,6 +394,15 @@
}
+/***********
+** send **
+***********/
+
+static void udsl_process_send (unsigned long data)
+{
+}
+
+
/************
** ATM **
************/
@@ -770,7 +802,7 @@
struct udsl_instance_data *instance;
unsigned char mac_str [13];
unsigned char mac [6];
- int i, err;
+ int i;
PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n",
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
@@ -785,8 +817,7 @@
/* instance init */
if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
PDEBUG ("No memory for Instance data!\n");
- err = -ENOMEM;
- goto fail_instance;
+ return -ENOMEM;
}
memset (instance, 0, sizeof (struct udsl_instance_data));
@@ -805,20 +836,25 @@
skb_queue_head_init (&instance->sndqueue);
- /* receive urb init */
+ spin_lock_init (&instance->send_lock);
+ INIT_LIST_HEAD (&instance->spare_senders);
+ INIT_LIST_HEAD (&instance->spare_buffers);
+
+ tasklet_init (&instance->send_tasklet, udsl_process_send, (unsigned long)
+instance);
+ INIT_LIST_HEAD (&instance->filled_buffers);
+
+ /* receive init */
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_receiver *rcv = &(instance->all_receivers[i]);
if (!(rcv->skb = dev_alloc_skb (UDSL_RCV_BUFFER_SIZE *
ATM_CELL_SIZE))) {
PDEBUG ("No memory for skb %d!\n", i);
- err = -ENOMEM;
- goto fail_urbs;
+ goto fail;
}
if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) {
PDEBUG ("No memory for receive urb %d!\n", i);
- err = -ENOMEM;
- goto fail_urbs;
+ goto fail;
}
rcv->instance = instance;
@@ -828,23 +864,35 @@
PDEBUG ("skb->truesize = %d (asked for %d)\n", rcv->skb->truesize,
UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE);
}
+ /* send init */
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
struct udsl_usb_send_data_context *snd = &(instance->send_ctx[i]);
if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) {
PDEBUG ("No memory for send urb %d!\n", i);
- err = -ENOMEM;
- goto fail_urbs;
+ goto fail;
}
snd->instance = instance;
+
+ list_add (&snd->list, &instance->spare_senders);
+ }
+
+ for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++) {
+ struct udsl_send_buffer *buf = &(instance->all_buffers[i]);
+
+ if (!(buf->base = kmalloc (UDSL_SND_BUFFER_SIZE * ATM_CELL_SIZE,
+GFP_KERNEL))) {
+ PDEBUG ("No memory for send buffer %d!\n", i);
+ goto fail;
+ }
+
+ list_add (&buf->list, &instance->spare_buffers);
}
/* atm init */
if (!(instance->atm_dev = atm_dev_register (udsl_driver_name,
&udsl_atm_devops, -1, 0))) {
PDEBUG ("failed to register ATM device!\n");
- err = -ENOMEM;
- goto fail_atm;
+ goto fail;
}
instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
@@ -871,14 +919,12 @@
return 0;
-fail_atm:
-fail_urbs:
- for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
- struct udsl_usb_send_data_context *snd = &(instance->send_ctx[i]);
+fail:
+ for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
+ kfree (instance->all_buffers[i].base);
- if (snd->urb)
- usb_free_urb (snd->urb);
- }
+ for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
+ usb_free_urb (instance->send_ctx[i].urb);
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_receiver *rcv = &(instance->all_receivers[i]);
@@ -886,12 +932,12 @@
if (rcv->skb)
kfree_skb (rcv->skb);
- if (rcv->urb)
- usb_free_urb (rcv->urb);
+ usb_free_urb (rcv->urb);
}
+
kfree (instance);
-fail_instance:
- return err;
+
+ return -ENOMEM;
}
static void udsl_usb_disconnect (struct usb_interface *intf)
@@ -900,7 +946,7 @@
struct list_head *pos;
unsigned long flags;
unsigned int count = 0;
- int i;
+ int result, i;
PDEBUG ("disconnecting\n");
@@ -913,8 +959,9 @@
tasklet_disable (&instance->receive_tasklet);
+ /* flush spare receivers */
down (&instance->serialize); /* vs udsl_fire_receivers */
- /* no need to take the spinlock - receive_tasklet is not running */
+ /* no need to take the spinlock */
list_for_each (pos, &instance->spare_receivers)
if (++count > UDSL_NUMBER_RCV_URBS)
panic (__FILE__ ": memory corruption detected at line %d!\n",
__LINE__);
@@ -926,7 +973,8 @@
count = UDSL_NUMBER_RCV_URBS - count;
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++)
- usb_unlink_urb (instance->all_receivers[i].urb);
+ if ((result = usb_unlink_urb (instance->all_receivers[i].urb)) < 0)
+ PDEBUG ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d
+returned %d\n", i, result);
/* wait for completion handlers to finish */
do {
@@ -943,12 +991,11 @@
if (completed == count)
break;
- /* not all urbs completed */
yield ();
} while (1);
- PDEBUG ("udsl_usb_disconnect: flushing %u completed receivers\n", count);
- /* no need to take the spinlock - no completion handlers running */
+ PDEBUG ("udsl_usb_disconnect: flushing\n");
+ /* no need to take the spinlock */
INIT_LIST_HEAD (&instance->completed_receivers);
tasklet_enable (&instance->receive_tasklet);
@@ -962,24 +1009,49 @@
kfree_skb (rcv->skb);
}
- for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
- struct udsl_usb_send_data_context *ctx = &(instance->send_ctx[i]);
+ udsl_atm_stopdevice (instance);
- usb_unlink_urb (ctx->urb);
+ tasklet_disable (&instance->send_tasklet);
- if (ctx->skb)
- ctx->vcc->pop (ctx->vcc, ctx->skb);
- ctx->skb = NULL;
+ for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
+ if ((result = usb_unlink_urb (instance->send_ctx[i].urb)) < 0)
+ PDEBUG ("udsl_usb_disconnect: usb_unlink_urb on send urb %d
+returned %d\n", i, result);
- usb_free_urb (ctx->urb);
+ /* wait for completion handlers to finish */
+ do {
+ count = 0;
+ spin_lock_irqsave (&instance->send_lock, flags);
+ list_for_each (pos, &instance->spare_senders)
+ if (++count > UDSL_NUMBER_SND_URBS)
+ panic (__FILE__ ": memory corruption detected at line
+%d!\n", __LINE__);
+ spin_unlock_irqrestore (&instance->send_lock, flags);
- }
+ PDEBUG ("udsl_usb_disconnect: found %u spare senders\n", count);
+ if (count == UDSL_NUMBER_SND_URBS)
+ break;
+
+ yield ();
+ } while (1);
+
+ PDEBUG ("udsl_usb_disconnect: flushing\n");
+ /* no need to take the spinlock */
+ INIT_LIST_HEAD (&instance->spare_senders);
+ INIT_LIST_HEAD (&instance->spare_buffers);
+ instance->current_buffer = NULL;
+
+ tasklet_enable (&instance->receive_tasklet);
+ tasklet_kill (&instance->receive_tasklet);
+
+ PDEBUG ("udsl_usb_disconnect: freeing senders\n");
+ for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
+ usb_free_urb (instance->send_ctx[i].urb);
- /* removing atm device */
- if (instance->atm_dev)
- udsl_atm_stopdevice (instance);
+ PDEBUG ("udsl_usb_disconnect: freeing buffers\n");
+ for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
+ kfree (instance->all_buffers[i].base);
+ PDEBUG ("udsl_usb_disconnect: freeing instance\n");
kfree (instance);
}
-------------------------------------------------------
This SF.NET email is sponsored by:
SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See!
http://www.vasoftware.com
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel