PERFORCE change 131607 for review

Hans Petter Selasky hselasky at FreeBSD.org
Tue Dec 25 11:45:23 PST 2007


http://perforce.freebsd.org/chv.cgi?CH=131607

Change 131607 by hselasky at hselasky_laptop001 on 2007/12/25 19:45:00

	
	Fixes for USB Device Side Mode.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#87 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#87 (text+ko) ====

@@ -1214,7 +1214,6 @@
 				} else {
 					mtx_unlock(info->usb_mtx);
 				}
-
 			}
 		}
 	}
@@ -1500,7 +1499,6 @@
 			/*
 		         * This is not a valid operation!
 		         */
-
 			PRINTFN(-1, ("Invalid parameter "
 			    "combination\n"));
 			goto error;
@@ -2756,6 +2754,7 @@
 		/* handle the request */
 		err = usbd_handle_request(xfer);
 
+		if (err) {
 		if (err == USBD_BAD_CONTEXT) {
 			/*
 			 * Currently we get a "start" context by
@@ -2765,12 +2764,11 @@
 			    USB_BUS_EXPLORE_TREE);
 			return;
 		}
-		if ((!xfer->flags_int.control_act) || err) {
 			/*
 		         * If no control transfer is active,
 		         * receive the next SETUP message:
 		         */
-			goto tr_start;
+			goto tr_restart;
 		}
 		usbd_start_hardware(xfer);
 		return;
@@ -2778,24 +2776,18 @@
 	default:
 		if (xfer->error != USBD_CANCELLED) {
 			/* should not happen - try stalling */
-			err = USBD_STALLED;
-			goto tr_start;
+			goto tr_restart;
 		}
 		break;
 	}
 	return;
 
-tr_start:
+tr_restart:
 	xfer->frlengths[0] = sizeof(usb_device_request_t);
 	xfer->nframes = 1;
 	xfer->flags.manual_status = 1;
 	xfer->flags.force_short_xfer = 0;
-	xfer->flags.short_xfer_ok = 0;
-	if (err) {
-		xfer->flags.stall_pipe = 1;
-	} else {
-		xfer->flags.stall_pipe = 0;
-	}
+	xfer->flags.stall_pipe = 1; /* cancel previous transfer, if any */
 	usbd_start_hardware(xfer);
 	return;
 }
@@ -2821,64 +2813,20 @@
 	}
 
 	if (usbd_set_config_index(xfer->udev, conf_no, 0)) {
+		PRINTFN(0, ("set config %d failed\n", conf_no));
 		mtx_lock(xfer->priv_mtx);
 		return (USBD_STALLED);
 	}
 	if (usbd_probe_and_attach(xfer->udev, USB_IFACE_INDEX_ANY)) {
-		mtx_lock(xfer->priv_mtx);
-		return (USBD_STALLED);
-	}
-	mtx_lock(xfer->priv_mtx);
-
-	return (0);
-}
-
-/*------------------------------------------------------------------------*
- *	usbd_handle_set_alt_setting
- *------------------------------------------------------------------------*/
-static usbd_status_t
-usbd_handle_set_alt_setting(struct usbd_xfer *xfer,
-    uint8_t iface_index, uint8_t alt_index)
-{
-	if (iface_index >= USB_MAX_INTERFACES) {
-		return (USBD_STALLED);
-	}
-	mtx_unlock(xfer->priv_mtx);
-
-	usbd_detach_device(xfer->udev, iface_index, 1);
-
-	if (usbd_set_alt_interface_index(xfer->udev,
-	    iface_index, alt_index)) {
-		mtx_lock(xfer->priv_mtx);
-		return (USBD_STALLED);
-	}
-	if (usbd_probe_and_attach(xfer->udev, iface_index)) {
+		PRINTFN(0, ("probe and attach failed\n"));
 		mtx_lock(xfer->priv_mtx);
 		return (USBD_STALLED);
 	}
 	mtx_lock(xfer->priv_mtx);
-
 	return (0);
 }
 
 /*------------------------------------------------------------------------*
- *	usbd_handle_get_alt_setting
- *------------------------------------------------------------------------*/
-static usbd_status_t
-usbd_handle_get_alt_setting(struct usbd_xfer *xfer,
-    uint8_t iface_index, uint8_t *ptr)
-{
-	struct usbd_interface *iface;
-
-	iface = usbd_get_iface(xfer->udev, iface_index);
-	if (iface) {
-		*ptr = iface->alt_index;
-		return (0);
-	}
-	return (USBD_STALLED);
-}
-
-/*------------------------------------------------------------------------*
  *	usbd_handle_set_stall_sub
  *
  * This function is used to make a BULK or INTERRUPT endpoint
@@ -3005,24 +2953,33 @@
 
 /*------------------------------------------------------------------------*
  *	usbd_handle_request
+ *
+ * Returns:
+ * 0: Ready to start hardware
+ * USBD_BAD_CONTEXT: Need to switch context
+ * Else: Stall current transfer, if any
  *------------------------------------------------------------------------*/
 static usbd_status_t
 usbd_handle_request(struct usbd_xfer *xfer)
 {
+/*
+ * USB handle request states
+ *
+ * Typical state sequence:
+ *
+ * ST_DATA [ -> ST_CONTEXT_START ] -> ST_POST_STATUS
+ */
 	enum {
 		ST_DATA,
 		ST_CONTEXT_START,
 		ST_POST_STATUS,
 	};
-
-	/*
-         * State sequence:
-         *
-         * ST_DATA [ -> ST_CONTEXT_START ] -> ST_POST_STATUS
-         */
 	usb_device_request_t req;
 	struct usbd_device *udev;
-	const void *ptr;
+	struct usbd_interface *iface;
+	const void *src_zcopy;		/* zero-copy source pointer */
+	const void *src_mcopy;		/* non zero-copy source pointer */
+	int error;
 	uint16_t off;			/* data offset */
 	uint16_t rem;			/* data remainder */
 	uint16_t max_len;		/* max fragment length */
@@ -3041,15 +2998,17 @@
 
 	switch (USBD_GET_STATE(xfer)) {
 	case USBD_ST_SETUP:
+		state = ST_CONTEXT_START;
+
 		if (!xfer->flags_int.control_act) {
 			/* nothing to do */
-			return (0);
+			goto tr_stalled;
 		}
+
 		if (xfer->flags_int.context != USBD_CONTEXT_START) {
-			/* wrong context */
+			/* wrong context - should not happen */
 			goto tr_bad_context;
 		}
-		state = ST_CONTEXT_START;
 		break;
 
 	default:			/* USBD_ST_TRANSFERRED */
@@ -3085,7 +3044,8 @@
 	/* set some defaults */
 
 	max_len = 0;
-	ptr = &temp;
+	src_zcopy = NULL;
+	src_mcopy = NULL;
 	udev = xfer->udev;
 
 	/* get some request fields decoded */
@@ -3093,9 +3053,9 @@
 	wValue = UGETW(req.wValue);
 	wIndex = UGETW(req.wIndex);
 
-	PRINTFN(2, ("req 0x%02x 0x%02x 0x%04x 0x%04x "
-	    "off=0x%x rem=0x%x\n", req.bmRequestType,
-	    req.bRequest, wValue, wIndex, off, rem));
+	PRINTFN(0, ("req 0x%02x 0x%02x 0x%04x 0x%04x "
+	    "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType,
+	    req.bRequest, wValue, wIndex, off, rem, state));
 
 	/* demultiplex the control request */
 
@@ -3130,7 +3090,7 @@
 	case UT_WRITE_ENDPOINT:
 		switch (req.bRequest) {
 		case UR_CLEAR_FEATURE:
-			switch (UGETW(req.wValue)) {
+			switch (wValue) {
 			case UF_ENDPOINT_HALT:
 				goto tr_handle_clear_halt;
 			case UF_DEVICE_REMOTE_WAKEUP:
@@ -3141,7 +3101,7 @@
 			break;
 
 		case UR_SET_FEATURE:
-			switch (UGETW(req.wValue)) {
+			switch (wValue) {
 			case UF_ENDPOINT_HALT:
 				goto tr_handle_set_halt;
 			case UF_DEVICE_REMOTE_WAKEUP:
@@ -3163,60 +3123,35 @@
 			goto tr_stalled;
 		}
 		break;
-
-	case UT_WRITE_INTERFACE:
-		switch (req.bRequest) {
-		case UR_SET_INTERFACE:
-			goto tr_handle_set_interface;
-		default:
-			goto tr_stalled;
-		}
-		break;
-
-	case UT_READ_INTERFACE:
-		switch (req.bRequest) {
-		case UR_GET_INTERFACE:
-			goto tr_handle_get_interface;
-		default:
-			goto tr_stalled;
+	default:
+		if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
+			if (state == ST_DATA) {
+				goto tr_bad_context;
+			}
+			goto tr_handle_iface_request;
 		}
-		break;
-
-	case UT_WRITE_CLASS_INTERFACE:
-	case UT_WRITE_VENDOR_INTERFACE:
-		/* XXX forward */
-		break;
-
-	case UT_READ_CLASS_INTERFACE:
-	case UT_READ_VENDOR_INTERFACE:
-		/* XXX forward */
-		break;
-	default:
 		goto tr_stalled;
 	}
 	goto tr_valid;
 
 tr_handle_get_descriptor:
-	usbd_temp_get_desc(udev, &req, &ptr, &max_len);
-	if (ptr == NULL) {
+	usbd_temp_get_desc(udev, &req, &src_zcopy, &max_len);
+	if (src_zcopy == NULL) {
 		goto tr_stalled;
 	}
-	/* use zero copy */
-	usbd_set_frame_data(xfer, USBD_ADD_BYTES(ptr, off), 1);
-	ptr = NULL;
-	/* adjust maximum length according to offset */
-	max_len -= off;
 	goto tr_valid;
 
 tr_handle_get_config:
+	temp.buf[0] = udev->curr_config_no;
+	src_mcopy = temp.buf;
 	max_len = 1;
-	temp.buf[0] = udev->curr_config_no;
 	goto tr_valid;
 
 tr_handle_get_status:
-	max_len = sizeof(temp.wStatus);
 	/* XXX FIXME */
 	USETW(temp.wStatus, UDS_SELF_POWERED);
+	src_mcopy = temp.wStatus;
+	max_len = sizeof(temp.wStatus);
 	goto tr_valid;
 
 tr_handle_set_address:
@@ -3238,7 +3173,7 @@
 	if (state == ST_DATA) {
 		goto tr_bad_context;
 	} else if (state == ST_CONTEXT_START) {
-		if (usbd_handle_set_config(xfer, wValue)) {
+		if (usbd_handle_set_config(xfer, req.wValue[0])) {
 			goto tr_stalled;
 		}
 	}
@@ -3246,7 +3181,7 @@
 
 tr_handle_clear_halt:
 	if (state == ST_DATA) {
-		if (usbd_handle_set_stall(xfer, wIndex, 0)) {
+		if (usbd_handle_set_stall(xfer, req.wIndex[0], 0)) {
 			goto tr_stalled;
 		}
 	}
@@ -3264,7 +3199,7 @@
 
 tr_handle_set_halt:
 	if (state == ST_DATA) {
-		if (usbd_handle_set_stall(xfer, wIndex, 1)) {
+		if (usbd_handle_set_stall(xfer, req.wIndex[0], 1)) {
 			goto tr_stalled;
 		}
 	}
@@ -3282,32 +3217,80 @@
 
 tr_handle_get_ep_status:
 	if (state == ST_DATA) {
+		temp.wStatus[0] =
+		    usbd_handle_get_stall(udev, req.wIndex[0]);
+		temp.wStatus[1] = 0;
+		src_mcopy = temp.wStatus;
 		max_len = sizeof(temp.wStatus);
-		temp.wStatus[0] = usbd_handle_get_stall(udev, req.wIndex[0]);
-		temp.wStatus[1] = 0;
 	}
 	goto tr_valid;
 
-tr_handle_set_interface:
-	if (state == ST_DATA) {
-		goto tr_bad_context;
-	} else if (state == ST_CONTEXT_START) {
-		if (usbd_handle_set_alt_setting(xfer, wIndex - 1, wValue)) {
+tr_handle_iface_request:
+	iface = usbd_get_iface(udev, req.wIndex[0]);
+	if (iface == NULL) {
+		goto tr_stalled;
+	}
+	if (iface->subdev == NULL) {
+		goto tr_handle_iface_request_builtin;
+	}
+	if (device_is_attached(iface->subdev) == 0) {
+		goto tr_handle_iface_request_builtin;
+	}
+	mtx_unlock(xfer->priv_mtx);
+
+	/* We use "USBD_ADD_BYTES" to de-const the src_zcopy */
+
+	error = USB_HANDLE_REQUEST(iface->subdev,
+	    &req, USBD_ADD_BYTES(&src_zcopy, 0), &max_len,
+	    off, (state == ST_POST_STATUS));
+
+	mtx_lock(xfer->priv_mtx);
+
+	if (error == 0) {
+		/* negativly adjust pointer and length */
+		src_zcopy = ((const uint8_t *)src_zcopy) - off;
+		max_len += off;
+		goto tr_valid;
+	} else if (error == ENOTTY) {
+		goto tr_stalled;
+	}
+	goto tr_handle_iface_request_builtin;
+
+tr_handle_iface_request_builtin:
+	switch (req.bmRequestType) {
+	case UT_WRITE_INTERFACE:
+		switch (req.bRequest) {
+		case UR_SET_INTERFACE:
+			if (iface->alt_index != req.wValue[0]) {
+				goto tr_stalled;
+			}
+			break;
+		default:
 			goto tr_stalled;
 		}
-	}
-	goto tr_valid;
+		break;
+
+	case UT_READ_INTERFACE:
+		switch (req.bRequest) {
+		case UR_GET_INTERFACE:
+			src_mcopy = &(iface->alt_index);
+			max_len = 1;
+			break;
 
-tr_handle_get_interface:
-	if (state == ST_DATA) {
-		if (usbd_handle_get_alt_setting(xfer, wIndex, temp.buf)) {
+		default:
 			goto tr_stalled;
 		}
-		max_len = 1;
+		break;
 	}
 	goto tr_valid;
 
 tr_valid:
+	if (state == ST_POST_STATUS) {
+	  goto tr_stalled;
+	}
+	/* subtract offset from length */
+
+	max_len -= off;
 
 	/* Compute the real maximum data length */
 
@@ -3340,8 +3323,13 @@
 		xfer->nframes = max_len ? 2 : 1;
 	}
 	if (max_len > 0) {
-		if (ptr) {
-			usbd_copy_in(xfer->frbuffers + 1, 0, ptr, max_len);
+		if (src_mcopy) {
+			src_mcopy = USBD_ADD_BYTES(src_mcopy, off);
+			usbd_copy_in(xfer->frbuffers + 1, 0, 
+				src_mcopy, max_len);
+		} else {
+			usbd_set_frame_data(xfer,
+			    USBD_ADD_BYTES(src_zcopy, off), 1);
 		}
 		xfer->frlengths[1] = max_len;
 	} else {
@@ -3350,12 +3338,16 @@
 		xfer->frlengths[1] = 0;
 	}
 	xfer->flags.stall_pipe = 0;	/* do not stall pipe */
+	PRINTFN(0, ("success\n"));
 	return (0);			/* success */
 
 tr_stalled:
+	PRINTFN(0, ("%s\n", (state == ST_POST_STATUS) ? 
+	   "complete" : "stalled"));
 	return (USBD_STALLED);
 
 tr_bad_context:
+	PRINTFN(0, ("bad context\n"));
 	return (USBD_BAD_CONTEXT);
 }
 
@@ -3367,7 +3359,7 @@
 		.bufsize = 1024,	/* bytes */
 		.mh.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
 		.mh.callback = &usbd_do_request_callback,
-		.md.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
+		.md.flags = {.proxy_buffer = 1,.short_xfer_ok = 0,},
 		.md.callback = &usbd_handle_request_callback,
 	},
 };


More information about the p4-projects mailing list