summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_compat_linux.c
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2009-11-01 21:48:18 +0000
committerthompsa <thompsa@FreeBSD.org>2009-11-01 21:48:18 +0000
commited3301cfd4f4cc549f3eb8ae53cd31e701a91312 (patch)
tree37a3a245ec1841c59f644e449a09e3456f60a109 /sys/dev/usb/usb_compat_linux.c
parent6f1a85be85a9aaa84bca1ae060e20dcd5b0f76fa (diff)
downloadFreeBSD-src-ed3301cfd4f4cc549f3eb8ae53cd31e701a91312.zip
FreeBSD-src-ed3301cfd4f4cc549f3eb8ae53cd31e701a91312.tar.gz
- Add usb_fill_bulk_urb() and usb_bulk_msg() linux compat functions [1]
- Don't write actual length if the actual length pointer is NULL [2] - correct Linux Compatibility error codes for short isochronous IN transfers and make status field signed. Submitted by: Leunam Elebek [1], Manuel Gebele [2]
Diffstat (limited to 'sys/dev/usb/usb_compat_linux.c')
-rw-r--r--sys/dev/usb/usb_compat_linux.c80
1 files changed, 73 insertions, 7 deletions
diff --git a/sys/dev/usb/usb_compat_linux.c b/sys/dev/usb/usb_compat_linux.c
index 604ac4d..b95a4f6 100644
--- a/sys/dev/usb/usb_compat_linux.c
+++ b/sys/dev/usb/usb_compat_linux.c
@@ -624,10 +624,11 @@ usb_start_wait_urb(struct urb *urb, usb_timeout_t timeout, uint16_t *p_actlen)
done:
if (do_unlock)
mtx_unlock(&Giant);
- if (err) {
- *p_actlen = 0;
- } else {
- *p_actlen = urb->actual_length;
+ if (p_actlen != NULL) {
+ if (err)
+ *p_actlen = 0;
+ else
+ *p_actlen = urb->actual_length;
}
return (err);
}
@@ -1362,8 +1363,17 @@ usb_linux_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
for (x = 0; x < urb->number_of_packets; x++) {
uipd = urb->iso_frame_desc + x;
+ if (uipd->length > xfer->frlengths[x]) {
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ /* XXX should be EREMOTEIO */
+ uipd->status = -EPIPE;
+ } else {
+ uipd->status = 0;
+ }
+ } else {
+ uipd->status = 0;
+ }
uipd->actual_length = xfer->frlengths[x];
- uipd->status = 0;
if (!xfer->flags.ext_buffer) {
usbd_copy_out(xfer->frbuffers, offset,
USB_ADD_BYTES(urb->transfer_buffer,
@@ -1385,8 +1395,8 @@ usb_linux_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
if (xfer->actlen < xfer->sumlen) {
/* short transfer */
if (urb->transfer_flags & URB_SHORT_NOT_OK) {
- urb->status = -EPIPE; /* XXX should be
- * EREMOTEIO */
+ /* XXX should be EREMOTEIO */
+ urb->status = -EPIPE;
} else {
urb->status = 0;
}
@@ -1482,6 +1492,7 @@ tr_setup:
/* Set zero for "actual_length" */
for (x = 0; x < urb->number_of_packets; x++) {
urb->iso_frame_desc[x].actual_length = 0;
+ urb->iso_frame_desc[x].status = urb->status;
}
/* call callback */
@@ -1663,3 +1674,58 @@ setup_bulk:
goto tr_setup;
}
}
+
+/*------------------------------------------------------------------------*
+ * usb_fill_bulk_urb
+ *------------------------------------------------------------------------*/
+void
+usb_fill_bulk_urb(struct urb *urb, struct usb_device *udev,
+ struct usb_host_endpoint *uhe, void *buf,
+ int length, usb_complete_t callback, void *arg)
+{
+ urb->dev = udev;
+ urb->endpoint = uhe;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = length;
+ urb->complete = callback;
+ urb->context = arg;
+}
+
+/*------------------------------------------------------------------------*
+ * usb_bulk_msg
+ *
+ * NOTE: This function can also be used for interrupt endpoints!
+ *
+ * Return values:
+ * 0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+int
+usb_bulk_msg(struct usb_device *udev, struct usb_host_endpoint *uhe,
+ void *data, int len, uint16_t *pactlen, usb_timeout_t timeout)
+{
+ struct urb *urb;
+ int err;
+
+ if (uhe == NULL)
+ return (-EINVAL);
+ if (len < 0)
+ return (-EINVAL);
+
+ err = usb_setup_endpoint(udev, uhe, 4096 /* bytes */);
+ if (err)
+ return (err);
+
+ urb = usb_alloc_urb(0, 0);
+ if (urb == NULL)
+ return (-ENOMEM);
+
+ usb_fill_bulk_urb(urb, udev, uhe, data, len,
+ usb_linux_wait_complete, NULL);
+
+ err = usb_start_wait_urb(urb, timeout, pactlen);
+
+ usb_free_urb(urb);
+
+ return (err);
+}
OpenPOWER on IntegriCloud