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