Hi Sebastian, On Tuesday, 17 July 2018 01:53:57 EEST Sebastian Andrzej Siewior wrote: > On 2018-07-13 09:47:28 [+0200], To Greg Kroah-Hartman wrote: > > sure. Let me refresh my old usb_fill_int_urb() series with this instead. > > The series is at > > https://git.kernel.org/pub/scm/linux/kernel/git/bigeasy/staging.git/log/?h= > usb-iso > > and needs double checking before it can be posted (and addressing the > few comments I had so far). Do you plan to send it in the near future ? I know this all started with simple patches and grew to a more complex patch series, but please don't give up, your work is valuable. > Here are just the highlights: > - usb_fill_iso_urb() itself: > > +static inline void usb_fill_iso_urb(struct urb *urb, > + struct usb_device *dev, > + unsigned int pipe, > + void *transfer_buffer, > + int buffer_length, > + usb_complete_t complete_fn, > + void *context, > + int interval, > + unsigned int packets, > + unsigned int packet_size) > +{ > + unsigned int i; > + > + urb->dev = dev; > + urb->pipe = pipe; > + urb->transfer_buffer = transfer_buffer; > + urb->transfer_buffer_length = buffer_length; > + urb->complete = complete_fn; > + urb->context = context; > + > + interval = clamp(interval, 1, 16); > + urb->interval = 1 << (interval - 1); > + urb->start_frame = -1; > + > + if (packets) > + urb->number_of_packets = packets; > + > + if (packet_size) { > + for (i = 0; i < packets; i++) { > + urb->iso_frame_desc[i].offset = packet_size * i; > + urb->iso_frame_desc[i].length = packet_size; > + } > + } > +} > > My understanding is that ->start_frame is only a return parameter. The > value is either implicit zero (via kzalloc()/memset()) or explicit > assignment to 0 or -1. So since it is a return value an init to 0 would > not be required and an initialisation to -1 (like for INT) would be > okay. Am I wrong? > > sound/ is (almost) the only part where struct usb_iso_packet_descriptor > init does not fit. It looks like it is done just before urb_submit() and > could be avoided there (moved to the init funtcion instead). However I > avoided changing it and added a zero check for `packet_size' so it can > be skipped. I also need to check if the `interval' value here to see if > it works as expected. Two examples: > > diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c > index c90607ebe155..f1d4e90e1d23 100644 > --- a/sound/usb/endpoint.c > +++ b/sound/usb/endpoint.c > @@ -772,6 +772,8 @@ static int data_ep_set_params(struct snd_usb_endpoint > *ep, /* allocate and initialize data urbs */ > for (i = 0; i < ep->nurbs; i++) { > struct snd_urb_ctx *u = &ep->urb[i]; > + void *buf; > + > u->index = i; > u->ep = ep; > u->packets = urb_packs; > @@ -783,16 +785,14 @@ static int data_ep_set_params(struct snd_usb_endpoint > *ep, if (!u->urb) > goto out_of_memory; > > - u->urb->transfer_buffer = > - usb_alloc_coherent(ep->chip->dev, u->buffer_size, > - GFP_KERNEL, &u->urb->transfer_dma); > - if (!u->urb->transfer_buffer) > + buf = usb_alloc_coherent(ep->chip->dev, u->buffer_size, > + GFP_KERNEL, &u->urb->transfer_dma); > + if (!buf) > goto out_of_memory; > - u->urb->pipe = ep->pipe; > + usb_fill_iso_urb(u->urb, NULL, ep->pipe, buf, u->buffer_size, > + snd_complete_urb, u, ep->datainterval + 1, 0, > + 0); > u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; > - u->urb->interval = 1 << ep->datainterval; > - u->urb->context = u; > - u->urb->complete = snd_complete_urb; > INIT_LIST_HEAD(&u->ready_list); > } > > @@ -823,15 +823,12 @@ static int sync_ep_set_params(struct snd_usb_endpoint > *ep) u->urb = usb_alloc_urb(1, GFP_KERNEL); > if (!u->urb) > goto out_of_memory; > - u->urb->transfer_buffer = ep->syncbuf + i * 4; > + usb_fill_iso_urb(u->urb, NULL, ep->pipe, ep->syncbuf + i * 4, 4, > + snd_complete_urb, u, ep->syncinterval + 1, 1, > + 0); > + > u->urb->transfer_dma = ep->sync_dma + i * 4; > - u->urb->transfer_buffer_length = 4; > - u->urb->pipe = ep->pipe; > u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; > - u->urb->number_of_packets = 1; > - u->urb->interval = 1 << ep->syncinterval; > - u->urb->context = u; > - u->urb->complete = snd_complete_urb; > } > > ep->nurbs = SYNC_URBS; > > diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c > b/sound/usb/usx2y/usx2yhwdeppcm.c index 4fd9276b8e50..3928d0d50028 100644 > --- a/sound/usb/usx2y/usx2yhwdeppcm.c > +++ b/sound/usb/usx2y/usx2yhwdeppcm.c > @@ -325,6 +325,8 @@ static int usX2Y_usbpcm_urbs_allocate(struct > snd_usX2Y_substream *subs) /* allocate and initialize data urbs */ > for (i = 0; i < NRURBS; i++) { > struct urb **purb = subs->urb + i; > + void *buf; > + > if (*purb) { > usb_kill_urb(*purb); > continue; > @@ -334,18 +336,18 @@ static int usX2Y_usbpcm_urbs_allocate(struct > snd_usX2Y_substream *subs) usX2Y_usbpcm_urbs_release(subs); > return -ENOMEM; > } > - (*purb)->transfer_buffer = is_playback ? > - subs->usX2Y->hwdep_pcm_shm->playback : ( > - subs->endpoint == 0x8 ? > - subs->usX2Y->hwdep_pcm_shm->capture0x8 : > - subs->usX2Y->hwdep_pcm_shm->capture0xA); > - > - (*purb)->dev = dev; > - (*purb)->pipe = pipe; > - (*purb)->number_of_packets = nr_of_packs(); > - (*purb)->context = subs; > - (*purb)->interval = 1; > - (*purb)->complete = i_usX2Y_usbpcm_subs_startup; > + if (is_playback) { > + buf = subs->usX2Y->hwdep_pcm_shm->playback; > + } else { > + if (subs->endpoint == 0x8) > + buf = subs->usX2Y->hwdep_pcm_shm->capture0x8; > + else > + buf = subs->usX2Y->hwdep_pcm_shm->capture0xA; > + } > + usb_fill_iso_urb(*purb, dev, pipe, buf, > + subs->maxpacksize * nr_of_packs(), > + i_usX2Y_usbpcm_subs_startup, subs, 1, > + nr_of_packs(), 0); > } > return 0; > } > > The users in media/ look almost always the same, a random one: > > diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c > index 54b036d39c5b..2e60d6257596 100644 > --- a/drivers/media/usb/pwc/pwc-if.c > +++ b/drivers/media/usb/pwc/pwc-if.c > @@ -358,7 +358,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) > { > struct usb_device *udev; > struct urb *urb; > - int i, j, ret; > + int i, ret; > struct usb_interface *intf; > struct usb_host_interface *idesc = NULL; > int compression = 0; /* 0..3 = uncompressed..high */ > @@ -409,6 +409,8 @@ static int pwc_isoc_init(struct pwc_device *pdev) > > /* Allocate and init Isochronuous urbs */ > for (i = 0; i < MAX_ISO_BUFS; i++) { > + void *buf; > + > urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); > if (urb == NULL) { > pwc_isoc_cleanup(pdev); > @@ -416,29 +418,19 @@ static int pwc_isoc_init(struct pwc_device *pdev) > } > pdev->urbs[i] = urb; > PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb); > - > - urb->interval = 1; // devik > - urb->dev = udev; > - urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); > urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; > - urb->transfer_buffer = usb_alloc_coherent(udev, > - ISO_BUFFER_SIZE, > - GFP_KERNEL, > - &urb->transfer_dma); > - if (urb->transfer_buffer == NULL) { > + buf = usb_alloc_coherent(udev, ISO_BUFFER_SIZE, GFP_KERNEL, > + &urb->transfer_dma); > + if (buf == NULL) { > PWC_ERROR("Failed to allocate urb buffer %d\n", i); > pwc_isoc_cleanup(pdev); > return -ENOMEM; > } > - urb->transfer_buffer_length = ISO_BUFFER_SIZE; > - urb->complete = pwc_isoc_handler; > - urb->context = pdev; > - urb->start_frame = 0; > - urb->number_of_packets = ISO_FRAMES_PER_DESC; > - for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { > - urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; > - urb->iso_frame_desc[j].length = pdev->vmax_packet_size; > - } > + usb_fill_iso_urb(urb, udev, > + usb_rcvisocpipe(udev, pdev->vendpoint), > + buf, ISO_BUFFER_SIZE, pwc_isoc_handler, pdev, > + 1, ISO_FRAMES_PER_DESC, > + pdev->vmax_packet_size); > } > > /* link */ > > I remember Alan asked to mention that the `.length' value is always set > to the same value by the proposed function while it could have different > values (like [0].offset = 0, [0].length = 8, [1].offset = 8, [1].length > = 16, [2].offset = 24, …). Unless I missed something, everyone using the > same value for length. Except for usbfs which uses what userland passes: > > diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c > index 476dcc5f2da3..54294f1a6ce5 100644 > --- a/drivers/usb/core/devio.c > +++ b/drivers/usb/core/devio.c > @@ -1436,7 +1436,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, > struct usbdevfs_urb *uurb int i, ret, is_in, num_sgs = 0, ifnum = -1; > int number_of_packets = 0; > unsigned int stream_id = 0; > - void *buf; > + int pipe; > + void *buf = NULL; > unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK | > USBDEVFS_URB_BULK_CONTINUATION | > USBDEVFS_URB_NO_FSBR | > @@ -1631,22 +1632,20 @@ static int proc_do_submiturb(struct usb_dev_state > *ps, struct usbdevfs_urb *uurb } > totlen -= u; > } > + buf = NULL; > } else if (uurb->buffer_length > 0) { > if (as->usbm) { > unsigned long uurb_start = (unsigned long)uurb->buffer; > > - as->urb->transfer_buffer = as->usbm->mem + > - (uurb_start - as->usbm->vm_start); > + buf = as->usbm->mem + (uurb_start - as->usbm->vm_start); > } else { > - as->urb->transfer_buffer = kmalloc(uurb->buffer_length, > - GFP_KERNEL); > - if (!as->urb->transfer_buffer) { > + buf = kmalloc(uurb->buffer_length, GFP_KERNEL); > + if (!buf) { > ret = -ENOMEM; > goto error; > } > if (!is_in) { > - if (copy_from_user(as->urb->transfer_buffer, > - uurb->buffer, > + if (copy_from_user(buf, uurb->buffer, > uurb->buffer_length)) { > ret = -EFAULT; > goto error; > @@ -1658,16 +1657,10 @@ static int proc_do_submiturb(struct usb_dev_state > *ps, struct usbdevfs_urb *uurb * short. Clear the buffer so that the gaps > * don't leak kernel data to userspace. > */ > - memset(as->urb->transfer_buffer, 0, > - uurb->buffer_length); > + memset(buf, 0, uurb->buffer_length); > } > } > } > - as->urb->dev = ps->dev; > - as->urb->pipe = (uurb->type << 30) | > - __create_pipe(ps->dev, uurb->endpoint & 0xf) | > - (uurb->endpoint & USB_DIR_IN); > - > /* This tedious sequence is necessary because the URB_* flags > * are internal to the kernel and subject to change, whereas > * the USBDEVFS_URB_* flags are a user API and must not be changed. > @@ -1683,30 +1676,42 @@ static int proc_do_submiturb(struct usb_dev_state > *ps, struct usbdevfs_urb *uurb u |= URB_NO_INTERRUPT; > as->urb->transfer_flags = u; > > - as->urb->transfer_buffer_length = uurb->buffer_length; > - as->urb->setup_packet = (unsigned char *)dr; > - dr = NULL; > + pipe = (uurb->type << 30) | (uurb->endpoint & USB_DIR_IN) | > + __create_pipe(ps->dev, uurb->endpoint & 0xf); > + switch (uurb->type) { > + case USBDEVFS_URB_TYPE_CONTROL: > + usb_fill_control_urb(as->urb, ps->dev, pipe, (u8 *)dr, buf, > + uurb->buffer_length, async_completed, as); > + dr = NULL; > + break; > + > + case USBDEVFS_URB_TYPE_BULK: > + usb_fill_bulk_urb(as->urb, ps->dev, pipe, buf, > + uurb->buffer_length, async_completed, as); > + break; > + > + case USBDEVFS_URB_TYPE_INTERRUPT: > + usb_fill_int_urb(as->urb, ps->dev, pipe, buf, > + uurb->buffer_length, async_completed, as, > + ep->desc.bInterval); > + break; > + > + case USBDEVFS_URB_TYPE_ISO: > + usb_fill_iso_urb(as->urb, ps->dev, pipe, buf, > + uurb->buffer_length, async_completed, as, > + ep->desc.bInterval, number_of_packets, 0); > + for (totlen = u = 0; u < number_of_packets; u++) { > + as->urb->iso_frame_desc[u].offset = totlen; > + as->urb->iso_frame_desc[u].length = isopkt[u].length; > + totlen += isopkt[u].length; > + } > + break; > + > + } > + buf = NULL; > as->urb->start_frame = uurb->start_frame; > - as->urb->number_of_packets = number_of_packets; > as->urb->stream_id = stream_id; > > - if (ep->desc.bInterval) { > - if (uurb->type == USBDEVFS_URB_TYPE_ISO || > - ps->dev->speed == USB_SPEED_HIGH || > - ps->dev->speed >= USB_SPEED_SUPER) > - as->urb->interval = 1 << > - min(15, ep->desc.bInterval - 1); > - else > - as->urb->interval = ep->desc.bInterval; > - } > - > - as->urb->context = as; > - as->urb->complete = async_completed; > - for (totlen = u = 0; u < number_of_packets; u++) { > - as->urb->iso_frame_desc[u].offset = totlen; > - as->urb->iso_frame_desc[u].length = isopkt[u].length; > - totlen += isopkt[u].length; > - } > kfree(isopkt); > isopkt = NULL; > as->ps = ps; > @@ -1777,6 +1782,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, > struct usbdevfs_urb *uurb dec_usb_memory_use_count(as->usbm, > &as->usbm->urb_use_count); > kfree(isopkt); > kfree(dr); > + kfree(buf); > if (as) > free_async(as); > return ret; > > > > thanks, > > > > > > greg k-h > > Sebastian -- Regards, Laurent Pinchart -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html