From owner-freebsd-usb@FreeBSD.ORG Thu Dec 4 16:02:18 2008 Return-Path: Delivered-To: freebsd-usb@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D7F7D1065677 for ; Thu, 4 Dec 2008 16:02:18 +0000 (UTC) (envelope-from hselasky@c2i.net) Received: from swip.net (mailfe15.swipnet.se [212.247.155.193]) by mx1.freebsd.org (Postfix) with ESMTP id 3FF368FC27 for ; Thu, 4 Dec 2008 16:02:17 +0000 (UTC) (envelope-from hselasky@c2i.net) X-Cloudmark-Score: 0.000000 [] X-Cloudmark-Analysis: v=1.0 c=1 a=X_LqtxM5jtcA:10 a=HnXr4FIqdIEA:10 a=P3SC899gXHkOLDnkTYxLZw==:17 a=Sh_yyNl-t6yRTb5XoCUA:9 a=6PRlk_uiLVK_tEjIRiwA:7 a=PDA6DmdfaypqPH2O7XWCtgz1LvcA:4 a=LY0hPdMaydYA:10 Received: from [62.113.133.240] (account mc467741@c2i.net [62.113.133.240] verified) by mailfe15.swip.net (CommuniGate Pro SMTP 5.2.6) with ESMTPA id 414896323; Thu, 04 Dec 2008 17:02:16 +0100 From: Hans Petter Selasky To: freebsd-usb@freebsd.org Date: Thu, 4 Dec 2008 17:04:26 +0100 User-Agent: KMail/1.9.7 References: <200812031559.54335.thierry.herbelot@free.fr> In-Reply-To: <200812031559.54335.thierry.herbelot@free.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200812041704.28290.hselasky@c2i.net> Cc: Thierry Herbelot Subject: Re: Asynchronous bulk transfers in usb2 ? X-BeenThere: freebsd-usb@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: FreeBSD support for USB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Dec 2008 16:02:18 -0000 On Wednesday 03 December 2008, Thierry Herbelot wrote: > Hello, > > I've been looking at the usb2 code, and from what I've understood, only > synchronous transfers are possible : a read (for exemple) is only scheduled > when the userland program calls usb_bulk_read(). > > Furthermore, only fixed size buffers are used : only one buffer of 32 kbyte > per transfer. This seems sub-optimal when reading (or writing) from > userland blocks bigger than 32 kbytes, as multiple kernel-to-userland > switches are necessary, and there is a latency window where no buffer > exists to accept data between the arrival of one block and the posting of > the next transfer. > > One way to work around this kind of limitations is to provide in advance a > certain number of transfers, arranged in a ring, where the callback > function at the end of a transfer schedules the next, without any further > userland intervention. > > Is there any project for adding asynchronous bulk reads and/or writes to > the fine usb2 stack ? Hi Thierry, There are two USB API's in the USB2 library. See man libusb20. The other API supports all of what you want to do. I.E. all of the USB functionality which is present in the kernel. --HPS Example code for the other USB API: struct libusb20_backend *pbe = libusb20_be_alloc_default(); struct libusb20_device *pdev = NULL; while ((pdev = libusb20_be_device_foreach(pbe, pdev))) { if (strstr(libusb20_dev_get_desc(pdev), argv[1])) { libusb20_be_dequeue_device(pbe, pdev); break; } } /* release data */ libusb20_be_free(pbe); if (pdev == NULL) { printf("No such device\n"); return (0); } printf("Trying to attach ...\n"); if (libusb20_dev_open(pdev, 2)) { err(1, "could not open device"); } xfer_in = libusb20_tr_get_pointer(pdev, 0); ep = 0x81; error = libusb20_tr_open(xfer_in, 65536 /* max block size */, 1 /* # of transfers */, ep /* endpoint */); if (error) { err(1, "could not open endpoint %u, %d", ep, error); } xfer_out = libusb20_tr_get_pointer(pdev, 1); ep = 0x01; error = libusb20_tr_open(xfer_out, 65536, 1, ep); if (error) { err(1, "could not open endpoint %u, %d", ep, error); } usb_pdev = pdev; libusb20_tr_clear_stall_sync(xfer_in); libusb20_tr_clear_stall_sync(xfer_out); do_io(struct libusb20_transfer *xfer, void *buf, uint32_t len, uint32_t timeout) { struct libusb20_device *pdev = usb_pdev; uint32_t max; uint32_t alen; uint32_t slen = 0; if (libusb20_tr_pending(xfer)) { return (-1); /* error */ } repeat: max = libusb20_tr_get_max_total_length(xfer); if (max > len) max = len; //There is also a function to setup multiple bulk transfers at the //same time. See man libusb20 libusb20_tr_setup_bulk(xfer, buf, max, timeout); libusb20_tr_start(xfer); while (libusb20_dev_process(pdev) == 0) { if (libusb20_tr_pending(xfer) == 0) { break; } // there is also an FD that you can poll! // See the libusb20_dev_wait_process() code. libusb20_dev_wait_process(pdev, -1); } if (libusb20_tr_get_status(xfer)) return (-1); alen = libusb20_tr_get_actual_length(xfer); slen += alen; if (alen == max) { len -= alen; if (len) goto repeat; } return (slen); }