Author: thompsa
Date: Sun Nov  1 21:48:18 2009
New Revision: 198776
URL: http://svn.freebsd.org/changeset/base/198776

Log:
  - 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]

Modified:
  head/sys/dev/usb/usb_compat_linux.c
  head/sys/dev/usb/usb_compat_linux.h

Modified: head/sys/dev/usb/usb_compat_linux.c
==============================================================================
--- head/sys/dev/usb/usb_compat_linux.c Sun Nov  1 21:44:37 2009        
(r198775)
+++ head/sys/dev/usb/usb_compat_linux.c Sun Nov  1 21:48:18 2009        
(r198776)
@@ -624,10 +624,11 @@ usb_start_wait_urb(struct urb *urb, usb_
 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 
 
                        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 
                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);
+}

Modified: head/sys/dev/usb/usb_compat_linux.h
==============================================================================
--- head/sys/dev/usb/usb_compat_linux.h Sun Nov  1 21:44:37 2009        
(r198775)
+++ head/sys/dev/usb/usb_compat_linux.h Sun Nov  1 21:48:18 2009        
(r198776)
@@ -217,7 +217,7 @@ struct usb_iso_packet_descriptor {
                                         * packets are usually back to back) */
        uint16_t length;                /* expected length */
        uint16_t actual_length;
-       uint16_t status;
+        int16_t status;                /* transfer status */
 };
 
 /*
@@ -299,6 +299,11 @@ void       usb_set_intfdata(struct usb_interfa
 void   usb_linux_register(void *arg);
 void   usb_linux_deregister(void *arg);
 
+void   usb_fill_bulk_urb(struct urb *, struct usb_device *,
+           struct usb_host_endpoint *, void *, int, usb_complete_t, void *);
+int    usb_bulk_msg(struct usb_device *, struct usb_host_endpoint *,
+           void *, int, uint16_t *, usb_timeout_t);
+
 #define        interface_to_usbdev(intf) (intf)->linux_udev
 #define        interface_to_bsddev(intf) (intf)->linux_udev
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to