On 13/02/15(Fri) 00:28, David Higgs wrote: > I guess nobody else has tried calling uhidev_get_report_async() yet. :) > > First I was getting a NULL pointer deref in the uhidev async callback. > Then I realized that due to USBD_NO_COPY, xfer->buffer was always > NULL. Next, I tried to use the DMA buffer, but I ended up in DDB in a > very cryptic way. I believe this is because the DMA buffer isn't > available when the callback is invoked. > > For the async callback to get a valid dmabuf, it needs to be invoked > prior to usb_freemem() in usbd_transfer_complete(). The xfer->status > determination would need to move up too. I'd do this myself but I > don't understand the logic and ordering of pipe->repeat stuff, and am > concerned about unintentionally breaking other devices. > > This is partially my fault, because I "tested" the original diff that > added the USBD_NO_COPY semantics to verify that it didn't break my > synchronous code paths, but hadn't yet written anything for upd(4) to > check the async ones.
Does the diff below help? Index: uhidev.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uhidev.c,v retrieving revision 1.69 diff -u -p -r1.69 uhidev.c --- uhidev.c 22 Jan 2015 10:27:47 -0000 1.69 +++ uhidev.c 13 Feb 2015 05:58:06 -0000 @@ -55,6 +55,7 @@ #include <dev/usb/usbdivar.h> #include <dev/usb/hid.h> #include <dev/usb/usb_quirks.h> +#include <dev/usb/usb_mem.h> #include <dev/usb/uhidev.h> @@ -747,15 +748,17 @@ void uhidev_get_report_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status err) { struct uhidev_async_info *info = priv; + char *buffer; int len = -1; if (err == USBD_NORMAL_COMPLETION || err == USBD_SHORT_XFER) { + buffer = KERNADDR(&xfer->dmabuf, 0); len = xfer->actlen; if (info->id > 0) { len--; - memcpy(info->data, xfer->buffer + 1, len); + memcpy(info->data, buffer + 1, len); } else { - memcpy(info->data, xfer->buffer, len); + memcpy(info->data, buffer, len); } } info->callback(info->priv, info->id, info->data, len);