PERFORCE change 145019 for review

Hans Petter Selasky hselasky at FreeBSD.org
Thu Jul 10 14:10:57 UTC 2008


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

Change 145019 by hselasky at hselasky_laptop001 on 2008/07/10 14:10:41

	
	Bugfixes and improvements with regard to LibUSB support.
	(Does not affect any other parts of the USB subsystem.)

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.c#14 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.c#13 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.c#14 (text+ko) ====

@@ -283,18 +283,21 @@
 	struct usb2_fifo **ppf;
 	struct usb2_fifo *f;
 	int fflags;
+	uint8_t need_uref;
 
 	if (fp) {
-		/*
-		 * Get the device location which should be valid and
-		 * correct:
-		 */
+		/* check if we need uref hint */
+		need_uref = devloc ? 0 : 1;
+		/* get devloc - already verified */
 		devloc = USB_P2U(fp->f_data);
+		/* get file flags */
 		fflags = fp->f_flag;
 		/* only ref FIFO */
 		ploc->is_uref = 0;
 		/* devloc should be valid */
 	} else {
+		/* we need uref */
+		need_uref = 1;
 		/* only ref device */
 		fflags = 0;
 		/* search for FIFO */
@@ -405,8 +408,13 @@
 		}
 	}
 	if (ploc->is_uref) {
-		DPRINTF(1, "ref udev\n");
-		ploc->udev->refcount++;
+		if (need_uref) {
+			DPRINTF(1, "ref udev - needed\n");
+			ploc->udev->refcount++;
+		} else {
+			DPRINTF(1, "ref udev - not needed\n");
+			ploc->is_uref = 0;
+		}
 	}
 	mtx_unlock(&usb2_ref_lock);
 
@@ -781,6 +789,9 @@
 	/* reset error flag */
 	f->flag_iserror = 0;
 
+	/* reset complete flag */
+	f->flag_iscomplete = 0;
+
 	/* reset select flag */
 	f->flag_isselect = 0;
 
@@ -1308,20 +1319,38 @@
 
 /* ARGSUSED */
 static int
-usb2_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td)
+usb2_poll_f(struct file *fp, int events,
+    struct ucred *cred, struct thread *td)
 {
 	struct usb2_location loc;
 	struct usb2_fifo *f;
 	struct usb2_mbuf *m;
 	int fflags;
 	int revents;
+	uint8_t usbfs_active = 0;
 
-	revents = usb2_ref_device(fp, &loc, 0);;
+	revents = usb2_ref_device(fp, &loc, 1 /* no uref */ );;
 	if (revents) {
 		return (POLLHUP);
 	}
 	fflags = fp->f_flag;
 
+	/* figure out if the USB File System is active */
+
+	if (fflags & FWRITE) {
+		f = loc.txfifo;
+		if (f->fs_ep_max != 0) {
+			usbfs_active = 1;
+		}
+	}
+	if (fflags & FREAD) {
+		f = loc.rxfifo;
+		if (f->fs_ep_max != 0) {
+			usbfs_active = 1;
+		}
+	}
+	/* Figure out who needs service */
+
 	if ((events & (POLLOUT | POLLWRNORM)) &&
 	    (fflags & FWRITE)) {
 
@@ -1329,10 +1358,23 @@
 
 		mtx_lock(f->priv_mtx);
 
-		/* check if any packets are available */
-		USB_IF_POLL(&(f->free_q), m);
+		if (!usbfs_active) {
+			if (f->flag_iserror) {
+				/* we got an error */
+				m = (void *)1;
+			} else {
+				/* check if any packets are available */
+				USB_IF_POLL(&(f->free_q), m);
+			}
+		} else {
+			if (f->flag_iscomplete) {
+				m = (void *)1;
+			} else {
+				m = NULL;
+			}
+		}
 
-		if (f->flag_iserror || f->flag_iscomplete || m) {
+		if (m) {
 			revents |= events & (POLLOUT | POLLWRNORM);
 		} else {
 			f->flag_isselect = 1;
@@ -1348,10 +1390,23 @@
 
 		mtx_lock(f->priv_mtx);
 
-		/* check if any packets are available */
-		USB_IF_POLL(&(f->used_q), m);
+		if (!usbfs_active) {
+			if (f->flag_iserror) {
+				/* we have and error */
+				m = (void *)1;
+			} else {
+				/* check if any packets are available */
+				USB_IF_POLL(&(f->used_q), m);
+			}
+		} else {
+			if (f->flag_iscomplete) {
+				m = (void *)1;
+			} else {
+				m = NULL;
+			}
+		}
 
-		if (f->flag_iserror || f->flag_iscomplete || m) {
+		if (m) {
 			revents |= events & (POLLIN | POLLRDNORM);
 		} else {
 			f->flag_isselect = 1;
@@ -1369,7 +1424,8 @@
 
 /* ARGSUSED */
 static int
-usb2_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
+usb2_read_f(struct file *fp, struct uio *uio, struct ucred *cred,
+    int flags, struct thread *td)
 {
 	struct usb2_location loc;
 	struct usb2_fifo *f;
@@ -1386,7 +1442,7 @@
 	if (fflags & O_DIRECT)
 		fflags |= IO_DIRECT;
 
-	err = usb2_ref_device(fp, &loc, 0);
+	err = usb2_ref_device(fp, &loc, 1 /* no uref */ );
 	if (err) {
 		return (ENXIO);
 	}
@@ -1408,7 +1464,16 @@
 	}
 	while (uio->uio_resid > 0) {
 
-		USB_IF_DEQUEUE(&(f->used_q), m);
+		if (f->fs_ep_max == 0) {
+			USB_IF_DEQUEUE(&(f->used_q), m);
+		} else {
+			/*
+			 * The queue is used for events that should be
+			 * retrieved using the "USB_FS_COMPLETE"
+			 * ioctl.
+			 */
+			m = NULL;
+		}
 
 		if (m == NULL) {
 
@@ -1424,6 +1489,8 @@
 				err = EWOULDBLOCK;
 				break;
 			}
+			DPRINTF(0, "sleeping\n");
+
 			err = usb2_fifo_wait(f);
 			if (err) {
 				break;
@@ -1489,7 +1556,8 @@
 
 /* ARGSUSED */
 static int
-usb2_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
+usb2_write_f(struct file *fp, struct uio *uio, struct ucred *cred,
+    int flags, struct thread *td)
 {
 	struct usb2_location loc;
 	struct usb2_fifo *f;
@@ -1507,7 +1575,7 @@
 	if (fflags & O_DIRECT)
 		fflags |= IO_DIRECT;
 
-	err = usb2_ref_device(fp, &loc, 0);
+	err = usb2_ref_device(fp, &loc, 1 /* no uref */ );
 	if (err) {
 		return (ENXIO);
 	}
@@ -1530,7 +1598,16 @@
 	}
 	while (uio->uio_resid > 0) {
 
-		USB_IF_DEQUEUE(&(f->free_q), m);
+		if (f->fs_ep_max == 0) {
+			USB_IF_DEQUEUE(&(f->free_q), m);
+		} else {
+			/*
+			 * The queue is used for events that should be
+			 * retrieved using the "USB_FS_COMPLETE"
+			 * ioctl.
+			 */
+			m = NULL;
+		}
 
 		if (m == NULL) {
 
@@ -1542,6 +1619,8 @@
 				err = EWOULDBLOCK;
 				break;
 			}
+			DPRINTF(0, "sleeping\n");
+
 			err = usb2_fifo_wait(f);
 			if (err) {
 				break;

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.c#13 (text+ko) ====

@@ -261,7 +261,6 @@
 			return (EIO);
 		}
 		break;
-
 	default:
 		return (EINVAL);
 	}
@@ -995,6 +994,7 @@
 	f->fs_ep_max = 0;
 	f->fs_ep_ptr = NULL;
 	f->flag_iscomplete = 0;
+	f->flag_no_uref = 0;		/* restore operation */
 	usb2_fifo_free_buffer(f);
 	return (0);
 }
@@ -1025,6 +1025,11 @@
 
 	USB_IF_DEQUEUE(&(f->free_q), m);
 
+	if (m == NULL) {
+		/* can happen during close */
+		DPRINTF(0, "out of buffers\n");
+		return;
+	}
 	USB_MBUF_RESET(m);
 
 	*((uint8_t *)(m->cur_data_ptr)) = index;
@@ -1044,7 +1049,8 @@
 	struct usb2_device_request *req;
 	struct usb2_xfer *xfer;
 	struct usb2_fs_endpoint fs_ep;
-	void *uaddr;
+	void *uaddr;			/* userland pointer */
+	void *kaddr;
 	uint32_t offset;
 	uint32_t length;
 	uint32_t n;
@@ -1066,6 +1072,11 @@
 	}
 	mtx_unlock(f->priv_mtx);
 
+	error = copyin(f->fs_ep_ptr +
+	    ep_index, &fs_ep, sizeof(fs_ep));
+	if (error) {
+		return (error);
+	}
 	/* security checks */
 
 	if (fs_ep.nFrames > xfer->max_frame_count) {
@@ -1076,11 +1087,6 @@
 		xfer->error = USB_ERR_INVAL;
 		goto complete;
 	}
-	error = copyin(f->fs_ep_ptr +
-	    ep_index, &fs_ep, sizeof(fs_ep));
-	if (error) {
-		return (error);
-	}
 	error = copyin(fs_ep.ppBuffer,
 	    &uaddr, sizeof(uaddr));
 	if (error) {
@@ -1102,7 +1108,7 @@
 			xfer->error = USB_ERR_INVAL;
 			goto complete;
 		}
-		if (length) {
+		if (length != 0) {
 			error = copyin(uaddr, req, length);
 			if (error) {
 				return (error);
@@ -1185,24 +1191,21 @@
 				break;
 			}
 			if (xfer->flags_int.isochronous_xfr) {
-
-				/* move data */
-				error = copyin(uaddr, USB_ADD_BYTES(
-				    xfer->frbuffers[0].buffer,
-				    offset), length);
-				if (error) {
-					break;
-				}
+				/* get kernel buffer address */
+				kaddr = xfer->frbuffers[0].buffer;
+				kaddr = USB_ADD_BYTES(kaddr, offset);
 			} else {
 				/* set current frame offset */
 				usb2_set_frame_offset(xfer, offset, n);
 
-				/* move data */
-				error = copyin(uaddr, xfer->frbuffers[n].buffer,
-				    length);
-				if (error) {
-					break;
-				}
+				/* get kernel buffer address */
+				kaddr = xfer->frbuffers[n].buffer;
+			}
+
+			/* move data */
+			error = copyin(uaddr, kaddr, length);
+			if (error) {
+				break;
 			}
 		}
 		offset += length;
@@ -1222,13 +1225,16 @@
 	struct usb2_device_request *req;
 	struct usb2_xfer *xfer;
 	struct usb2_fs_endpoint fs_ep;
-	void *uaddr;
+	struct usb2_fs_endpoint *fs_ep_uptr;	/* userland ptr */
+	void *uaddr;			/* userland ptr */
+	void *kaddr;
 	uint32_t offset;
 	uint32_t length;
 	uint32_t temp;
 	uint32_t n;
 	uint32_t rem;
 	int error;
+	uint8_t isread;
 
 	if (ep_index >= f->fs_ep_max) {
 		return (EINVAL);
@@ -1244,8 +1250,8 @@
 	}
 	mtx_unlock(f->priv_mtx);
 
-	error = copyin(f->fs_ep_ptr +
-	    ep_index, &fs_ep, sizeof(fs_ep));
+	fs_ep_uptr = f->fs_ep_ptr + ep_index;
+	error = copyin(fs_ep_uptr, &fs_ep, sizeof(fs_ep));
 	if (error) {
 		return (error);
 	}
@@ -1258,66 +1264,84 @@
 		req = xfer->frbuffers[0].buffer;
 
 		/* Host mode only ! */
-		if ((req->bmRequestType & (UT_READ | UT_WRITE)) == UT_WRITE) {
-			goto complete;
+		if ((req->bmRequestType & (UT_READ | UT_WRITE)) == UT_READ) {
+			isread = 1;
+		} else {
+			isread = 0;
 		}
-		n = 1;
+		if (xfer->nframes == 0)
+			n = 0;		/* should never happen */
+		else
+			n = 1;
 	} else {
 		/* Device and Host mode */
-		if (!USB_GET_DATA_ISREAD(xfer)) {
-			goto complete;
+		if (USB_GET_DATA_ISREAD(xfer)) {
+			isread = 1;
+		} else {
+			isread = 0;
 		}
 		n = 0;
 	}
 
+	/* Update lengths and copy out data */
+
 	rem = xfer->max_data_length;
+	offset = 0;
 
 	for (; n != xfer->nframes; n++) {
 
-		/* we need to know the destination buffer */
-		error = copyin(fs_ep.ppBuffer + n,
-		    &uaddr, sizeof(uaddr));
+		/* get initial length into "temp" */
+		error = copyin(fs_ep.pLength + n,
+		    &temp, sizeof(temp));
 		if (error) {
 			return (error);
 		}
-		if (xfer->flags_int.isochronous_xfr) {
+		if (temp > rem) {
+			/* the userland length has been corrupted */
+			DPRINTF(0, "corrupt userland length "
+			    "%u > %u\n", temp, rem);
+			fs_ep.status = USB_ERR_INVAL;
+			goto complete;
+		}
+		rem -= temp;
+
+		/* get actual transfer length */
+		length = xfer->frlengths[n];
+		if (length > temp) {
+			/* data overflow */
+			fs_ep.status = USB_ERR_INVAL;
+			DPRINTF(0, "data overflow %u > %u\n",
+			    length, temp);
+			goto complete;
+		}
+		if (isread) {
 
-			/* we need to know the initial length */
-			error = copyin(fs_ep.pLength + n,
-			    &length, sizeof(length));
+			/* we need to know the destination buffer */
+			error = copyin(fs_ep.ppBuffer + n,
+			    &uaddr, sizeof(uaddr));
 			if (error) {
 				return (error);
 			}
-			/* range check */
-			if (length > rem) {
-				fs_ep.status = USB_ERR_INVAL;
-				goto complete;
-			}
-			rem -= length;
-			temp = offset + length;
-
-			/* limit */
-			if (length > xfer->frlengths[n]) {
-				length = xfer->frlengths[n];
-			}
-			/* move data */
-			error = copyout(USB_ADD_BYTES(xfer->frbuffers[0].buffer,
-			    offset), uaddr, length);
-			if (error) {
-				return (error);
+			if (xfer->flags_int.isochronous_xfr) {
+				/* only one frame buffer */
+				kaddr = USB_ADD_BYTES(
+				    xfer->frbuffers[0].buffer, offset);
+			} else {
+				/* multiple frame buffers */
+				kaddr = xfer->frbuffers[n].buffer;
 			}
-			offset = temp;
-		} else {
-
-			length = xfer->frlengths[n];
 
 			/* move data */
-			error = copyout(xfer->frbuffers[n].buffer,
-			    uaddr, length);
+			error = copyout(kaddr, uaddr, length);
 			if (error) {
 				return (error);
 			}
 		}
+		/*
+		 * Update offset according to initial length, which is
+		 * needed by isochronous transfers!
+		 */
+		offset += temp;
 
 		/* update length */
 		error = copyout(&length,
@@ -1329,14 +1353,14 @@
 
 complete:
 	/* update "aFrames" */
-	error = copyout(&fs_ep.aFrames, &(f->fs_ep_ptr +
-	    ep_index)->aFrames, sizeof(fs_ep.aFrames));
+	error = copyout(&fs_ep.aFrames, &(fs_ep_uptr->aFrames),
+	    sizeof(fs_ep.aFrames));
 	if (error) {
 		return (error);
 	}
 	/* update "status" */
-	error = copyout(&fs_ep.status, &(f->fs_ep_ptr +
-	    ep_index)->status, sizeof(fs_ep.status));
+	error = copyout(&fs_ep.status, &(fs_ep_uptr->status),
+	    sizeof(fs_ep.status));
 	return (error);
 }
 
@@ -1392,7 +1416,7 @@
 			}
 			mtx_lock(f->priv_mtx);
 			usb2_transfer_start(f->fs_xfer[pd->ep_index]);
-			mtx_lock(f->priv_mtx);
+			mtx_unlock(f->priv_mtx);
 			break;
 		}
 	case USB_FS_STOP:{
@@ -1427,6 +1451,10 @@
 				error = EBUSY;
 				break;
 			}
+			if (f->flag_no_uref) {
+				error = EINVAL;
+				break;
+			}
 			if (f->dev_ep_index != 0) {
 				error = EINVAL;
 				break;
@@ -1459,9 +1487,6 @@
 				break;
 			}
 			error = ugen_fs_uninit(f);
-			if (error == 0) {
-				f->flag_no_uref = 0;	/* restore operation */
-			}
 			break;
 		}
 


More information about the p4-projects mailing list