summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_handle_request.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/usb_handle_request.c')
-rw-r--r--sys/dev/usb/usb_handle_request.c66
1 files changed, 39 insertions, 27 deletions
diff --git a/sys/dev/usb/usb_handle_request.c b/sys/dev/usb/usb_handle_request.c
index 23486ad..a720919 100644
--- a/sys/dev/usb/usb_handle_request.c
+++ b/sys/dev/usb/usb_handle_request.c
@@ -46,6 +46,7 @@
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
#include "usb_if.h"
#define USB_DEBUG_VAR usb_debug
@@ -181,6 +182,30 @@ done:
return (err);
}
+static usb_error_t
+usb_check_alt_setting(struct usb_device *udev,
+ struct usb_interface *iface, uint8_t alt_index)
+{
+ uint8_t do_unlock;
+ usb_error_t err = 0;
+
+ /* automatic locking */
+ if (sx_xlocked(udev->default_sx + 1)) {
+ do_unlock = 0;
+ } else {
+ do_unlock = 1;
+ sx_xlock(udev->default_sx + 1);
+ }
+
+ if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc))
+ err = USB_ERR_INVAL;
+
+ if (do_unlock) {
+ sx_unlock(udev->default_sx + 1);
+ }
+ return (err);
+}
+
/*------------------------------------------------------------------------*
* usb_handle_iface_request
*
@@ -285,42 +310,29 @@ tr_repeat:
switch (req.bRequest) {
case UR_SET_INTERFACE:
/*
- * Handle special case. If we have parent interface
- * we just reset the endpoints, because this is a
- * multi interface device and re-attaching only a
- * part of the device is not possible. Also if the
- * alternate setting is the same like before we just
- * reset the interface endoints.
- */
- if ((iface_parent != NULL) ||
- (iface->alt_index == req.wValue[0])) {
- error = usb_reset_iface_endpoints(udev,
- iface_index);
- if (error) {
- DPRINTF("alt setting failed %s\n",
- usbd_errstr(error));
- goto tr_stalled;
- }
- break;
- }
- /*
- * Doing the alternate setting will detach the
- * interface aswell:
+ * We assume that the endpoints are the same
+ * accross the alternate settings.
+ *
+ * Reset the endpoints, because re-attaching
+ * only a part of the device is not possible.
*/
- error = usbd_set_alt_interface_index(udev,
- iface_index, req.wValue[0]);
+ error = usb_check_alt_setting(udev,
+ iface, req.wValue[0]);
if (error) {
- DPRINTF("alt setting failed %s\n",
+ DPRINTF("alt setting does not exist %s\n",
usbd_errstr(error));
goto tr_stalled;
}
- error = usb_probe_and_attach(udev,
- iface_index);
+ error = usb_reset_iface_endpoints(udev, iface_index);
if (error) {
- DPRINTF("alt setting probe failed\n");
+ DPRINTF("alt setting failed %s\n",
+ usbd_errstr(error));
goto tr_stalled;
}
+ /* update the current alternate setting */
+ iface->alt_index = req.wValue[0];
break;
+
default:
goto tr_stalled;
}
OpenPOWER on IntegriCloud