Index: usb_atm.c =================================================================== RCS file: /home/cvs/usbatm/usb_atm.c,v retrieving revision 1.12 diff -u -r1.12 usb_atm.c --- usb_atm.c 29 Dec 2004 21:18:32 -0000 1.12 +++ usb_atm.c 23 Jan 2005 17:34:51 -0000 @@ -102,6 +102,7 @@ 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; +static unsigned int rcv_buf_per_urb = UDSL_DEFAULT_RCV_BUF_PER_URB; module_param(num_rcv_urbs, uint, 0444); MODULE_PARM_DESC(num_rcv_urbs, @@ -139,6 +140,12 @@ __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: " __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")"); +module_param(rcv_buf_per_urb, uint, 0444); +MODULE_PARM_DESC(rcv_buf_per_urb, + "Number of the buffer in iso urb used for reception (range: 0-" + __MODULE_STRING(UDSL_MAX_RCV_BUF_PER_URB) ", default: " + __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_PER_URB) ")"); + /* ATM */ static void udsl_atm_dev_close(struct atm_dev *dev); @@ -412,6 +419,38 @@ /************** ** receive ** **************/ +static inline void udsl_usb_fill_iso_urb (struct urb *urb, + struct usb_device *dev, + unsigned int pipe, + void *transfer_buffer, + int buffer_length, + int frame_size, + usb_complete_t complete, + void *context) +{ + int j; + + //spin_lock_init(&urb->lock); + urb->dev = dev; + urb->pipe = pipe; + urb->transfer_buffer = transfer_buffer; + urb->transfer_buffer_length = buffer_length; + urb->complete = complete; + urb->context = context; + + urb->interval = 1; + urb->transfer_flags = URB_ISO_ASAP; + urb->number_of_packets = rcv_buf_per_urb; + + for (j = 0; j < urb->number_of_packets; j++) { + urb->iso_frame_desc[j].offset = j * frame_size; + urb->iso_frame_desc[j].length = frame_size; + + urb->iso_frame_desc[j].status = 0; + urb->iso_frame_desc[j].actual_length = 0; + } + urb->status = 0; +} static void udsl_complete_receive(struct urb *urb, struct pt_regs *regs) { @@ -428,17 +467,45 @@ instance = rcv->instance; buf = rcv->buffer; - buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rcv_padding); + if ( urb->actual_length <= 0 && !urb->status) { + int err; + if ((err = usb_submit_urb(rcv->urb, GFP_ATOMIC)) < 0) { + dbg("udsl_complete_receive: urb submission failed (%d)!", 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); + tasklet_schedule(&instance->receive_tasklet); + } + return; + } + + if (instance->iso_data_endpoint) { + int i; + for (i = 0; i < urb->number_of_packets; i++) { + buf->frames[i].status = urb->iso_frame_desc[i].status; + buf->frames[i].filled_cells = urb->iso_frame_desc[i].actual_length / (ATM_CELL_SIZE + instance->rcv_padding); + UDSL_ASSERT(buf->frames[i].filled_cells <= instance->iso_frame_size); + vdbg("udsl_complete_receive: urb 0x%p, frame %d, status %d size %d", urb, i, buf->frames[i].status, buf->frames[i].filled_cells); + } + } + else { + buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rcv_padding); + } vdbg("udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p", urb, urb->status, urb->actual_length, buf->filled_cells, rcv, buf); - UDSL_ASSERT(buf->filled_cells <= rcv_buf_size); + if (!instance->iso_data_endpoint) + 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)) + if (likely(!urb->status) || + /* via chipset produce lot's of crc error...*/ + (instance->iso_data_endpoint && urb->status == -EILSEQ) + ) tasklet_schedule(&instance->receive_tasklet); spin_unlock_irqrestore(&instance->receive_lock, flags); } @@ -468,11 +535,22 @@ rcv->buffer = buf; - usb_fill_bulk_urb(rcv->urb, instance->usb_dev, - usb_rcvbulkpipe(instance->usb_dev, instance->data_endpoint), - buf->base, - rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding), - udsl_complete_receive, rcv); + /* refill the urb because the buf could have changed...*/ + /* urb->transfer_buffer and urb->context should be enought */ + if (instance->iso_data_endpoint) + udsl_usb_fill_iso_urb(rcv->urb, instance->usb_dev, + usb_rcvisocpipe(instance->usb_dev, instance->iso_data_endpoint), + buf->base, + instance->iso_frame_size * rcv_buf_per_urb, + instance->iso_frame_size, + udsl_complete_receive, rcv); + else + usb_fill_bulk_urb(rcv->urb, instance->usb_dev, + usb_rcvbulkpipe(instance->usb_dev, instance->data_endpoint), + buf->base, + rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding), + udsl_complete_receive, rcv); + vdbg("udsl_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); @@ -498,7 +576,16 @@ spin_unlock_irq(&instance->receive_lock); vdbg("udsl_process_receive: processing buf 0x%p", buf); - udsl_extract_cells(instance, buf->base, buf->filled_cells); + if (instance->iso_data_endpoint) { + int i; + for (i=0 ; i < rcv_buf_per_urb; i++) { + if (buf->frames[i].status == 0) { + udsl_extract_cells(instance, buf->base + i * instance->iso_frame_size, buf->frames[i].filled_cells); + } + } + } + else + udsl_extract_cells(instance, buf->base, buf->filled_cells); list_add(&buf->list, &instance->spare_receive_buffers); goto made_progress; } @@ -925,6 +1012,8 @@ { char *buf; int i, length; + int nb_frames = 0; + int urb_size = rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding); kref_init(&instance->refcount); /* one for USB */ udsl_get_instance(instance); /* one for ATM */ @@ -955,11 +1044,15 @@ (unsigned long)instance); INIT_LIST_HEAD(&instance->filled_send_buffers); + if (instance->iso_data_endpoint) { + nb_frames = rcv_buf_per_urb; + urb_size = instance->iso_frame_size * rcv_buf_per_urb; + } /* receive init */ for (i = 0; i < num_rcv_urbs; i++) { struct udsl_receiver *rcv = &(instance->receivers[i]); - if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { + if (!(rcv->urb = usb_alloc_urb(nb_frames, GFP_KERNEL))) { dbg("udsl_usb_probe: no memory for receive urb %d!", i); goto fail; } @@ -973,8 +1066,7 @@ struct udsl_receive_buffer *buf = &(instance->receive_buffers[i]); - buf->base = kmalloc(rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding), - GFP_KERNEL); + buf->base = kmalloc(urb_size, GFP_KERNEL); if (!buf->base) { dbg("udsl_usb_probe: no memory for receive buffer %d!", i); goto fail; @@ -1147,7 +1239,8 @@ || (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)) + || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE) + || (rcv_buf_per_urb > UDSL_MAX_RCV_BUF_PER_URB)) return -EINVAL; return 0; Index: usb_atm.h =================================================================== RCS file: /home/cvs/usbatm/usb_atm.h,v retrieving revision 1.4 diff -u -r1.4 usb_atm.h --- usb_atm.h 29 Dec 2004 21:18:32 -0000 1.4 +++ usb_atm.h 23 Jan 2005 17:34:51 -0000 @@ -51,21 +51,29 @@ #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_MAX_RCV_BUF_PER_URB 20 #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 */ +#define UDSL_DEFAULT_RCV_BUF_PER_URB 16 #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) /* receive */ +struct udsl_receive_iso_frame { + unsigned int filled_cells; + int status; +}; + struct udsl_receive_buffer { struct list_head list; unsigned char *base; + struct udsl_receive_iso_frame frames[UDSL_MAX_RCV_BUF_PER_URB]; unsigned int filled_cells; }; @@ -129,6 +137,8 @@ struct usb_device *usb_dev; char description[64]; int data_endpoint; + int iso_data_endpoint; + int iso_frame_size; int snd_padding; int rcv_padding; const char *driver_name;