From owner-p4-projects@FreeBSD.ORG Thu Jul 10 14:10:57 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 57E271065685; Thu, 10 Jul 2008 14:10:57 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1B67F106567F for ; Thu, 10 Jul 2008 14:10:57 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 147FF8FC2C for ; Thu, 10 Jul 2008 14:10:57 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m6AEAukK024697 for ; Thu, 10 Jul 2008 14:10:56 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.2/8.14.1/Submit) id m6AEAun8024695 for perforce@freebsd.org; Thu, 10 Jul 2008 14:10:56 GMT (envelope-from hselasky@FreeBSD.org) Date: Thu, 10 Jul 2008 14:10:56 GMT Message-Id: <200807101410.m6AEAun8024695@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 145019 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 10 Jul 2008 14:10:57 -0000 http://perforce.freebsd.org/chv.cgi?CH=145019 Change 145019 by hselasky@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; }