Index: usbatm.c =================================================================== RCS file: /home/cvs/usbatm/usbatm.c,v retrieving revision 1.15 diff -u -u -r1.15 usbatm.c --- usbatm.c 4 Mar 2005 11:30:58 -0000 1.15 +++ usbatm.c 18 Mar 2005 23:35:41 -0000 @@ -145,6 +145,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, @@ -182,6 +183,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 usbatm_atm_dev_close(struct atm_dev *dev); @@ -456,6 +463,37 @@ /************** ** receive ** **************/ +static inline void usbatm_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; + + 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 usbatm_complete_receive(struct urb *urb, struct pt_regs *regs) { @@ -472,17 +510,44 @@ instance = rcv->instance; buf = rcv->buffer; - buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rx_padding); + if ( urb->actual_length <= 0 && !urb->status) { + int err; + if ((err = usb_submit_urb(rcv->urb, GFP_ATOMIC)) < 0) { + dbg("usbatm_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 (usb_pipeisoc(instance->rx_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->rx_padding); + UDSL_ASSERT(buf->frames[i].filled_cells <= instance->iso_frame_size); + vdbg("usbatm_complete_receive: urb 0x%p, frame %d, status %d, actual_length %d ,filled_cells %d", urb, i, buf->frames[i].status, urb->iso_frame_desc[i].actual_length, buf->frames[i].filled_cells); + } + } + else { + buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rx_padding); + } vdbg("usbatm_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); + UDSL_ASSERT(usb_pipeisoc(instance->rx_endpoint) || + 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...*/ + (usb_pipeisoc(instance->rx_endpoint) && urb->status == -EILSEQ)) tasklet_schedule(&instance->receive_tasklet); spin_unlock_irqrestore(&instance->receive_lock, flags); } @@ -512,11 +577,21 @@ rcv->buffer = buf; - 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); + /* refill the urb because the buf could have changed...*/ + /* urb->transfer_buffer and urb->context should be enought */ + if (usb_pipeisoc(instance->rx_endpoint)) + usbatm_usb_fill_iso_urb(rcv->urb, instance->usb_dev, + instance->rx_endpoint, + buf->base, + instance->iso_frame_size * rcv_buf_per_urb, + instance->iso_frame_size, + usbatm_complete_receive, rcv); + else + 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); vdbg("usbatm_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); @@ -542,7 +617,17 @@ spin_unlock_irq(&instance->receive_lock); vdbg("usbatm_process_receive: processing buf 0x%p", buf); - usbatm_extract_cells(instance, buf->base, buf->filled_cells); + if (usb_pipeisoc(instance->rx_endpoint)) { + int i; + for (i=0 ; i < rcv_buf_per_urb; i++) { + if (buf->frames[i].status == 0) { + usbatm_extract_cells(instance, buf->base + i * instance->iso_frame_size, buf->frames[i].filled_cells); + } + } + } + else + usbatm_extract_cells(instance, buf->base, buf->filled_cells); + list_add(&buf->list, &instance->spare_receive_buffers); goto made_progress; } @@ -1040,6 +1125,8 @@ char *buf; int error = -ENOMEM; int i, length; + int nb_frames = 0; + int urb_size; int need_heavy; dev_dbg(&intf->dev, "trying driver %s with vendor=0x%x, product=0x%x, ifnum %d\n", @@ -1064,9 +1151,18 @@ instance->usb_dev = dev; instance->usb_intf = intf; instance->tx_endpoint = usb_sndbulkpipe(dev, driver->out); - instance->rx_endpoint = usb_rcvbulkpipe(dev, driver->in); + if (driver->iso_frame_size) { + nb_frames = rcv_buf_per_urb; + urb_size = driver->iso_frame_size * rcv_buf_per_urb; + instance->rx_endpoint = usb_rcvisocpipe(dev, driver->in); + } + else { + urb_size = rcv_buf_size * (ATM_CELL_SIZE + instance->rx_padding); + instance->rx_endpoint = usb_rcvbulkpipe(dev, driver->in); + } instance->tx_padding = driver->tx_padding; instance->rx_padding = driver->rx_padding; + instance->iso_frame_size = driver->iso_frame_size; buf = instance->description; length = sizeof(instance->description); @@ -1127,7 +1223,7 @@ for (i = 0; i < num_rcv_urbs; i++) { struct usbatm_receiver *rcv = &(instance->receivers[i]); - if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { + if (!(rcv->urb = usb_alloc_urb(nb_frames, GFP_KERNEL))) { dev_dbg(&intf->dev, "no memory for receive urb %d!\n", i); goto fail_unbind; } @@ -1140,8 +1236,7 @@ for (i = 0; i < num_rcv_bufs; i++) { struct usbatm_receive_buffer *buf = &(instance->receive_buffers[i]); - buf->base = kmalloc(rcv_buf_size * (ATM_CELL_SIZE + instance->rx_padding), - GFP_KERNEL); + buf->base = kmalloc(urb_size, GFP_KERNEL); if (!buf->base) { dev_dbg(&intf->dev, "no memory for receive buffer %d!\n", i); goto fail_unbind; @@ -1306,6 +1401,7 @@ || (num_rcv_bufs > UDSL_MAX_RCV_BUFS) || (num_snd_bufs > UDSL_MAX_SND_BUFS) || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE) + || (rcv_buf_per_urb > UDSL_MAX_RCV_BUF_PER_URB) || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE)) return -EINVAL; Index: usbatm.h =================================================================== RCS file: /home/cvs/usbatm/usbatm.h,v retrieving revision 1.10 diff -u -u -r1.10 usbatm.h --- usbatm.h 7 Feb 2005 23:50:41 -0000 1.10 +++ usbatm.h 18 Mar 2005 23:35:41 -0000 @@ -88,6 +88,7 @@ unsigned rx_padding; unsigned tx_padding; + unsigned iso_frame_size; /* if using iso urb, the size of a frame */ }; extern int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, @@ -103,19 +104,26 @@ #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 /* receive */ +struct udsl_receive_iso_frame { + unsigned int filled_cells; + int status; +}; struct usbatm_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; }; @@ -164,6 +172,7 @@ int rx_endpoint; int tx_padding; int rx_padding; + unsigned iso_frame_size; /* ATM device */ struct atm_dev *atm_dev;