PERFORCE change 144851 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Mon Jul 7 22:14:44 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=144851
Change 144851 by hselasky at hselasky_laptop001 on 2008/07/07 22:13:49
More patches to support LibUSB 1.0.
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.c#12 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.h#7 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.c#10 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.h#3 edit
.. //depot/projects/usb/src/sys/dev/usb2/include/usb2_ioctl.h#7 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.c#12 (text+ko) ====
@@ -77,7 +77,6 @@
static void usb2_dev_init_post(void *arg);
static void usb2_dev_uninit(void *arg);
static int usb2_fifo_uiomove(struct usb2_fifo *f, void *cp, int n, struct uio *uio);
-static void usb2_fifo_wakeup(struct usb2_fifo *f);
static void usb2_fifo_check_methods(struct usb2_fifo_methods *pm);
static void usb2_clone(void *arg, USB_UCRED char *name, int namelen, struct cdev **dev);
static struct usb2_fifo *usb2_fifo_alloc(void);
@@ -907,21 +906,77 @@
}
/*------------------------------------------------------------------------*
+ * usb2_check_thread_perm
+ *
+ * Returns:
+ * 0: Has permission.
+ * Else: No permission.
+ *------------------------------------------------------------------------*/
+int
+usb2_check_thread_perm(struct usb2_device *udev, struct thread *td,
+ int fflags, uint8_t iface_index, uint8_t ep_index)
+{
+ struct usb2_perm perm;
+ struct usb2_interface *iface;
+ int err;
+
+ iface = usb2_get_iface(udev, iface_index);
+ if (iface == NULL) {
+ return (EINVAL);
+ }
+ if (iface->idesc == NULL) {
+ return (EINVAL);
+ }
+ /* set default value */
+ bzero(&perm, sizeof(perm));
+
+ /* create a permissions mask */
+ perm.uid = td->td_ucred->cr_ruid;
+ perm.gid = td->td_ucred->cr_rgid;
+ perm.mode = 0;
+ if (fflags & FREAD)
+ perm.mode |= 0444;
+ if (fflags & FWRITE)
+ perm.mode |= 0222;
+ perm.active = 1;
+
+ mtx_lock(udev->default_mtx);
+
+ /* scan down the permissions tree */
+ if ((ep_index != 0) && iface &&
+ usb2_match_perm(&perm, &iface->perm)) {
+ /* we got access through the interface */
+ err = 0;
+ } else if (udev && usb2_match_perm(&perm, &udev->perm)) {
+ /* we got access through the device */
+ err = 0;
+ } else if (udev->bus && usb2_match_perm(&perm, &(udev->bus->perm))) {
+ /* we got access through the USB bus */
+ err = 0;
+ } else if (usb2_match_perm(&perm, &usb2_perm)) {
+ /* we got general access */
+ err = 0;
+ } else {
+ /* no access */
+ err = EPERM;
+ }
+ mtx_unlock(udev->default_mtx);
+ return (err);
+}
+
+/*------------------------------------------------------------------------*
* usb2_fdopen - cdev callback
*------------------------------------------------------------------------*/
static int
usb2_fdopen(struct cdev *dev, int xxx_oflags, struct thread *td, struct file *fp)
{
struct usb2_location loc;
- struct usb2_perm perm;
uint32_t devloc;
int err;
int fflags;
DPRINTF(1, "oflags=0x%08x\n", xxx_oflags);
- bzero(&perm, sizeof(perm));
-
devloc = usb2_last_devloc;
usb2_last_devloc = (0 - 1); /* reset "usb2_devloc" */
@@ -960,39 +1015,9 @@
DPRINTF(1, "cannot ref device\n");
return (ENXIO);
}
- /* create a permissions mask */
- perm.uid = td->td_ucred->cr_ruid;
- perm.gid = td->td_ucred->cr_rgid;
- perm.mode = 0;
- if (fflags & FREAD)
- perm.mode |= 0444;
- if (fflags & FWRITE)
- perm.mode |= 0222;
- perm.active = 1;
-
- mtx_lock(loc.udev->default_mtx);
+ err = usb2_check_thread_perm(loc.udev, td, fflags,
+ loc.iface_index, loc.ep_index);
- /* scan down the permissions tree */
- if ((loc.ep_index != 0) && loc.iface &&
- usb2_match_perm(&perm, &loc.iface->perm)) {
- /* we got access through the interface */
- err = 0;
- } else if (loc.udev && usb2_match_perm(&perm, &loc.udev->perm)) {
- /* we got access through the device */
- err = 0;
- } else if (loc.bus && usb2_match_perm(&perm, &loc.bus->perm)) {
- /* we got access through the USB bus */
- err = 0;
- } else if (usb2_match_perm(&perm, &usb2_perm)) {
- /* we got general access */
- err = 0;
- } else {
- /* no access */
- err = EPERM;
- }
-
- mtx_unlock(loc.udev->default_mtx);
-
/* check for error */
if (err) {
usb2_unref_device(&loc);
@@ -1281,7 +1306,6 @@
return (ENXIO);
}
-
/* ARGSUSED */
static int
usb2_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td)
@@ -1297,17 +1321,18 @@
return (POLLHUP);
}
fflags = fp->f_flag;
- f = loc.txfifo;
if ((events & (POLLOUT | POLLWRNORM)) &&
(fflags & FWRITE)) {
+ f = loc.txfifo;
+
mtx_lock(f->priv_mtx);
/* check if any packets are available */
USB_IF_POLL(&(f->free_q), m);
- if (f->flag_iserror || m) {
+ if (f->flag_iserror || f->flag_iscomplete || m) {
revents |= events & (POLLOUT | POLLWRNORM);
} else {
f->flag_isselect = 1;
@@ -1316,17 +1341,17 @@
mtx_unlock(f->priv_mtx);
}
- f = loc.rxfifo;
-
if ((events & (POLLIN | POLLRDNORM)) &&
(fflags & FREAD)) {
+ f = loc.rxfifo;
+
mtx_lock(f->priv_mtx);
/* check if any packets are available */
USB_IF_POLL(&(f->used_q), m);
- if (f->flag_iserror || m) {
+ if (f->flag_iserror || f->flag_iscomplete || m) {
revents |= events & (POLLIN | POLLRDNORM);
} else {
f->flag_isselect = 1;
@@ -1381,8 +1406,6 @@
err = EIO;
goto done;
}
- /* XXX TODO: support IO-vectors */
-
while (uio->uio_resid > 0) {
USB_IF_DEQUEUE(&(f->used_q), m);
@@ -1505,8 +1528,6 @@
err = EIO;
goto done;
}
- /* XXX TODO: support IO-vectors */
-
while (uio->uio_resid > 0) {
USB_IF_DEQUEUE(&(f->free_q), m);
@@ -1613,7 +1634,7 @@
return;
}
-static void
+void
usb2_fifo_wakeup(struct usb2_fifo *f)
{
usb2_fifo_signal(f);
==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.h#7 (text+ko) ====
@@ -74,8 +74,10 @@
struct usb2_fifo_methods *methods;
struct cdev *symlink[2]; /* our symlinks */
struct proc *async_p; /* process that wants SIGIO */
+ struct usb2_fs_endpoint *fs_ep_ptr;
struct usb2_device *udev;
struct usb2_xfer *xfer[2];
+ struct usb2_xfer **fs_xfer;
struct mtx *priv_mtx; /* client data */
struct file *curr_file; /* set if FIFO is opened by a FILE */
void *priv_sc0; /* client data */
@@ -87,6 +89,7 @@
uint16_t dev_ep_index; /* our device endpoint index */
uint8_t flag_no_uref; /* set if FIFO is not control endpoint */
uint8_t flag_sleeping; /* set if FIFO is sleeping */
+ uint8_t flag_iscomplete; /* set if a USB transfer is complete */
uint8_t flag_iserror; /* set if FIFO error happened */
uint8_t flag_isselect; /* set if FIFO is selected */
uint8_t flag_flushing; /* set if FIFO is flushing data */
@@ -96,6 +99,7 @@
uint8_t iface_index; /* set to the interface we belong to */
uint8_t fifo_index; /* set to the FIFO index in "struct
* usb2_device" */
+ uint8_t fs_ep_max;
uint8_t fifo_zlp; /* zero length packet count */
uint8_t refcount;
#define USB_FIFO_REF_MAX 0xFF
@@ -121,5 +125,7 @@
uint8_t usb2_fifo_opened(struct usb2_fifo *fifo);
void usb2_fifo_free(struct usb2_fifo *f);
void usb2_fifo_reset(struct usb2_fifo *f);
+int usb2_check_thread_perm(struct usb2_device *udev, struct thread *td, int fflags, uint8_t iface_index, uint8_t ep_index);
+void usb2_fifo_wakeup(struct usb2_fifo *f);
#endif /* _USB2_DEV_H_ */
==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.c#10 (text+ko) ====
@@ -43,6 +43,7 @@
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/core/usb2_hub.h>
#include <dev/usb2/core/usb2_generic.h>
+#include <dev/usb2/core/usb2_transfer.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
@@ -61,6 +62,7 @@
static usb2_callback_t ugen_default_write_callback;
static usb2_callback_t ugen_isoc_read_callback;
static usb2_callback_t ugen_isoc_write_callback;
+static usb2_callback_t ugen_default_fs_callback;
static usb2_fifo_open_t ugen_open;
static usb2_fifo_close_t ugen_close;
@@ -78,8 +80,11 @@
static int ugen_get_sdesc(struct usb2_fifo *f, struct usb2_gen_descriptor *ugd);
static int usb2_gen_fill_deviceinfo(struct usb2_fifo *f, struct usb2_device_info *di);
static int ugen_re_enumerate(struct usb2_fifo *f);
-static int ugen_iface_ioctl(struct usb2_fifo *f, u_long cmd, void *addr);
+static int ugen_iface_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags);
static int ugen_ctrl_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags);
+static int ugen_fs_uninit(struct usb2_fifo *f);
+static uint8_t ugen_fs_get_complete(struct usb2_fifo *f, uint8_t *pindex);
+
/* structures */
@@ -184,6 +189,10 @@
usb2_transfer_unsetup(f->xfer, 2);
usb2_fifo_free_buffer(f);
+
+ if (ugen_fs_uninit(f)) {
+ /* ignore any errors - we are closing */
+ }
return;
}
@@ -200,6 +209,10 @@
/* transfers are already opened */
return (0);
}
+ if (f->fs_xfer) {
+ /* should not happen */
+ return (EINVAL);
+ }
bzero(usb2_config, sizeof(usb2_config));
usb2_config[1].type = UE_CONTROL;
@@ -230,8 +243,8 @@
if (ugen_transfer_setup(f, usb2_config, 2)) {
return (EIO);
}
- /* first transfer clears stall */
- f->flag_stall = 1;
+ /* first transfer does not clear stall */
+ f->flag_stall = 0;
break;
case UE_ISOCHRONOUS:
@@ -269,6 +282,10 @@
/* transfers are already opened */
return (0);
}
+ if (f->fs_xfer) {
+ /* should not happen */
+ return (EINVAL);
+ }
bzero(usb2_config, sizeof(usb2_config));
usb2_config[1].type = UE_CONTROL;
@@ -300,8 +317,8 @@
if (ugen_transfer_setup(f, usb2_config, 2)) {
return (EIO);
}
- /* first transfer clears stall */
- f->flag_stall = 1;
+ /* first transfer does not clear stall */
+ f->flag_stall = 0;
break;
case UE_ISOCHRONOUS:
@@ -793,26 +810,25 @@
return (0);
}
-int
-ugen_do_request(struct usb2_fifo *f, struct usb2_ctl_request *ur)
+/*------------------------------------------------------------------------*
+ * ugen_check_request
+ *
+ * Return values:
+ * 0: Access allowed
+ * Else: No access
+ *------------------------------------------------------------------------*/
+static int
+ugen_check_request(struct usb2_device_request *req)
{
- int error;
- uint16_t len;
- uint16_t actlen;
- uint8_t isread;
- void *data = NULL;
-
- if (f->flag_no_uref) {
- /* control endpoint only */
- return (EINVAL);
- }
- /* avoid requests that would damage the bus integrity */
- if (((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE) &&
- (ur->ucr_request.bRequest == UR_SET_ADDRESS)) ||
- ((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE) &&
- (ur->ucr_request.bRequest == UR_SET_CONFIG)) ||
- ((ur->ucr_request.bmRequestType == UT_WRITE_INTERFACE) &&
- (ur->ucr_request.bRequest == UR_SET_INTERFACE))) {
+ /*
+ * Avoid requests that would damage the bus integrity:
+ */
+ if (((req->bmRequestType == UT_WRITE_DEVICE) &&
+ (req->bRequest == UR_SET_ADDRESS)) ||
+ ((req->bmRequestType == UT_WRITE_DEVICE) &&
+ (req->bRequest == UR_SET_CONFIG)) ||
+ ((req->bmRequestType == UT_WRITE_INTERFACE) &&
+ (req->bRequest == UR_SET_INTERFACE))) {
if (suser(curthread)) {
return (EPERM);
}
@@ -821,13 +837,32 @@
* Clearing the stall this way is not allowed, hence it does
* not update the data toggle value in "struct usb2_pipe" !
*/
- if (ur->ucr_request.bmRequestType == UT_WRITE_ENDPOINT) {
+ if (req->bmRequestType == UT_WRITE_ENDPOINT) {
if (suser(curthread)) {
return (EPERM);
}
}
/* TODO: add more checks to verify the interface index */
+ return (0);
+}
+
+int
+ugen_do_request(struct usb2_fifo *f, struct usb2_ctl_request *ur)
+{
+ int error;
+ uint16_t len;
+ uint16_t actlen;
+ uint8_t isread;
+ void *data = NULL;
+
+ if (f->flag_no_uref) {
+ /* control endpoint only */
+ return (EINVAL);
+ }
+ if (ugen_check_request(&ur->ucr_request)) {
+ return (EPERM);
+ }
len = UGETW(ur->ucr_request.wLength);
isread = (ur->ucr_request.bmRequestType & UT_READ) ? 1 : 0;
@@ -901,7 +936,648 @@
}
static int
-ugen_iface_ioctl(struct usb2_fifo *f, u_long cmd, void *addr)
+ugen_fs_uninit(struct usb2_fifo *f)
+{
+ if (f->fs_xfer == NULL) {
+ return (EINVAL);
+ }
+ usb2_transfer_unsetup(f->fs_xfer, f->fs_ep_max);
+ free(f->fs_xfer, M_USB);
+ f->fs_xfer = NULL;
+ f->fs_ep_max = 0;
+ f->fs_ep_ptr = NULL;
+ f->flag_iscomplete = 0;
+ usb2_fifo_free_buffer(f);
+ return (0);
+}
+
+static uint8_t
+ugen_fs_get_complete(struct usb2_fifo *f, uint8_t *pindex)
+{
+ struct usb2_mbuf *m;
+
+ USB_IF_DEQUEUE(&(f->used_q), m);
+
+ if (m) {
+ *pindex = *((uint8_t *)(m->cur_data_ptr));
+
+ USB_IF_ENQUEUE(&(f->free_q), m);
+
+ return (0); /* success */
+ } else {
+ f->flag_iscomplete = 0;
+ }
+ return (1); /* failure */
+}
+
+static void
+ugen_fs_set_complete(struct usb2_fifo *f, uint8_t index)
+{
+ struct usb2_mbuf *m;
+
+ USB_IF_DEQUEUE(&(f->free_q), m);
+
+ USB_MBUF_RESET(m);
+
+ *((uint8_t *)(m->cur_data_ptr)) = index;
+
+ USB_IF_ENQUEUE(&(f->used_q), m);
+
+ f->flag_iscomplete = 1;
+
+ usb2_fifo_wakeup(f);
+
+ return;
+}
+
+static int
+ugen_fs_copy_in(struct usb2_fifo *f, uint8_t ep_index)
+{
+ struct usb2_device_request *req;
+ struct usb2_xfer *xfer;
+ struct usb2_fs_endpoint fs_ep;
+ void *uaddr;
+ uint32_t offset;
+ uint32_t length;
+ uint32_t n;
+ uint32_t rem;
+ int error;
+ uint8_t isread;
+
+ if (ep_index >= f->fs_ep_max) {
+ return (EINVAL);
+ }
+ xfer = f->fs_xfer[ep_index];
+ if (xfer == NULL) {
+ return (EINVAL);
+ }
+ mtx_lock(f->priv_mtx);
+ if (usb2_transfer_pending(xfer)) {
+ mtx_unlock(f->priv_mtx);
+ return (EBUSY); /* should not happen */
+ }
+ mtx_unlock(f->priv_mtx);
+
+ /* security checks */
+
+ if (fs_ep.nFrames > xfer->max_frame_count) {
+ return (EINVAL);
+ }
+ if (fs_ep.nFrames == 0) {
+ return (EINVAL);
+ }
+ 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) {
+ return (error);
+ }
+ /* reset first frame */
+ usb2_set_frame_offset(xfer, 0, 0);
+
+ if (xfer->flags_int.control_xfr) {
+
+ req = xfer->frbuffers[0].buffer;
+
+ error = copyin(fs_ep.pLength,
+ &length, sizeof(length));
+ if (error) {
+ return (error);
+ }
+ if (length >= sizeof(*req)) {
+ return (EINVAL);
+ }
+ if (length) {
+ error = copyin(uaddr, req, length);
+ if (error) {
+ return (error);
+ }
+ }
+ if (ugen_check_request(req)) {
+ return (EPERM);
+ }
+ xfer->frlengths[0] = length;
+
+ /* Host mode only ! */
+ if ((req->bmRequestType &
+ (UT_READ | UT_WRITE)) == UT_READ) {
+ isread = 1;
+ } else {
+ isread = 0;
+ }
+ n = 1;
+ offset = sizeof(*req);
+
+ } else {
+ /* Device and Host mode */
+ if (USB_GET_DATA_ISREAD(xfer)) {
+ isread = 1;
+ } else {
+ isread = 0;
+ }
+ n = 0;
+ offset = 0;
+ }
+
+ rem = xfer->max_data_length;
+ xfer->nframes = fs_ep.nFrames;
+ xfer->timeout = fs_ep.timeout;
+ if (xfer->timeout > 65535) {
+ xfer->timeout = 65535;
+ }
+ if (fs_ep.flags & USB2_FS_FLAG_SINGLE_SHORT_OK)
+ xfer->flags.short_xfer_ok = 1;
+ else
+ xfer->flags.short_xfer_ok = 0;
+
+ if (fs_ep.flags & USB2_FS_FLAG_MULTI_SHORT_OK)
+ xfer->flags.short_frames_ok = 1;
+ else
+ xfer->flags.short_frames_ok = 0;
+
+ if (fs_ep.flags & USB2_FS_FLAG_FORCE_SHORT)
+ xfer->flags.force_short_xfer = 1;
+ else
+ xfer->flags.force_short_xfer = 0;
+
+ if (fs_ep.flags & USB2_FS_FLAG_CLEAR_STALL)
+ xfer->flags.stall_pipe = 1;
+ else
+ xfer->flags.stall_pipe = 0;
+
+ for (; n != xfer->nframes; n++) {
+
+ error = copyin(fs_ep.pLength + n,
+ &length, sizeof(length));
+ if (error) {
+ return (error);
+ }
+ xfer->frlengths[n] = length;
+
+ if (length > rem) {
+ return (EINVAL);
+ }
+ rem -= length;
+
+ if (!isread) {
+
+ if (xfer->flags_int.isochronous_xfr) {
+
+ /* move data */
+ error = copyin(USB_ADD_BYTES(uaddr, offset),
+ USB_ADD_BYTES(xfer->frbuffers[0].buffer,
+ offset), length);
+ if (error) {
+ return (error);
+ }
+ } else {
+ /* we need to know the source buffer */
+ error = copyin(fs_ep.ppBuffer + n,
+ &uaddr, sizeof(uaddr));
+ if (error) {
+ return (error);
+ }
+ /* set current frame offset */
+ usb2_set_frame_offset(xfer, offset, n);
+
+ /* move data */
+ error = copyin(uaddr, xfer->frbuffers[n].buffer,
+ length);
+ if (error) {
+ return (error);
+ }
+ }
+ }
+ offset += length;
+ }
+ return (error);
+}
+
+static int
+ugen_fs_copy_out(struct usb2_fifo *f, uint8_t ep_index)
+{
+ struct usb2_device_request *req;
+ struct usb2_xfer *xfer;
+ struct usb2_fs_endpoint fs_ep;
+ void *uaddr;
+ uint32_t offset;
+ uint32_t length;
+ uint32_t temp;
+ uint32_t n;
+ uint32_t rem;
+ int error;
+
+ if (ep_index >= f->fs_ep_max) {
+ return (EINVAL);
+ }
+ xfer = f->fs_xfer[ep_index];
+ if (xfer == NULL) {
+ return (EINVAL);
+ }
+ mtx_lock(f->priv_mtx);
+ if (usb2_transfer_pending(xfer)) {
+ mtx_unlock(f->priv_mtx);
+ return (EBUSY); /* should not happen */
+ }
+ mtx_unlock(f->priv_mtx);
+
+ error = copyin(f->fs_ep_ptr +
+ ep_index, &fs_ep, sizeof(fs_ep));
+ if (error) {
+ return (error);
+ }
+ fs_ep.status = xfer->error;
+ fs_ep.aFrames = xfer->aframes;
+ if (xfer->error) {
+ goto complete;
+ }
+ error = copyin(fs_ep.ppBuffer,
+ &uaddr, sizeof(uaddr));
+ if (error) {
+ return (error);
+ }
+ if (xfer->flags_int.control_xfr) {
+ req = xfer->frbuffers[0].buffer;
+
+ /* Host mode only ! */
+ if ((req->bmRequestType & (UT_READ | UT_WRITE)) == UT_WRITE) {
+ goto complete;
+ }
+ n = 1;
+ } else {
+ /* Device and Host mode */
+ if (!USB_GET_DATA_ISREAD(xfer)) {
+ goto complete;
+ }
+ n = 0;
+ }
+
+ rem = xfer->max_data_length;
+
+ for (; n != xfer->nframes; n++) {
+
+ if (xfer->flags_int.isochronous_xfr) {
+
+ /* we need to know the initial length */
+ error = copyin(fs_ep.pLength + n,
+ &length, sizeof(length));
+ if (error) {
+ return (error);
+ }
+ /* range check */
+ if (length > rem) {
+ return (EINVAL);
+ }
+ 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), USB_ADD_BYTES(uaddr, offset), length);
+ if (error) {
+ return (error);
+ }
+ offset = temp;
+ } else {
+
+ length = xfer->frlengths[n];
+
+ /* we need to know the destination buffer */
+ error = copyin(fs_ep.ppBuffer + n,
+ &uaddr, sizeof(uaddr));
+ if (error) {
+ return (error);
+ }
+ /* move data */
+ error = copyout(xfer->frbuffers[n].buffer,
+ uaddr, length);
+ if (error) {
+ return (error);
+ }
+ }
+
+ /* update length */
+ error = copyout(&length,
+ fs_ep.pLength + n, sizeof(length));
+ if (error) {
+ return (error);
+ }
+ }
+
+complete:
+ /* update "aFrames" */
+ error = copyout(&fs_ep.aFrames, &(f->fs_ep_ptr +
+ ep_index)->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));
+ return (error);
+}
+
+static uint8_t
+ugen_fifo_in_use(struct usb2_fifo *f, int fflags)
+{
+ struct usb2_fifo *f_rx;
+ struct usb2_fifo *f_tx;
+
+ f_rx = f->udev->fifo[(f->fifo_index & ~1) + USB_FIFO_RX];
+ f_tx = f->udev->fifo[(f->fifo_index & ~1) + USB_FIFO_TX];
+
+ if ((fflags & FREAD) && f_rx &&
+ (f_rx->xfer[0] || f_rx->xfer[1])) {
+ return (1); /* RX FIFO in use */
+ }
+ if ((fflags & FWRITE) && f_tx &&
+ (f_tx->xfer[0] || f_tx->xfer[1])) {
+ return (1); /* TX FIFO in use */
+ }
+ return (0); /* not in use */
+}
+
+static int
+ugen_fs_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags)
+{
+ int error = 0;
+
+ switch (cmd) {
+ case USB_FS_COMPLETE:{
+ struct usb2_fs_complete *pd = addr;
+ uint8_t ep_index;
+
+ mtx_lock(f->priv_mtx);
+ error = ugen_fs_get_complete(f, &ep_index);
+ mtx_unlock(f->priv_mtx);
+
+ if (error) {
+ error = EBUSY;
+ break;
+ }
+ pd->ep_index = ep_index;
+ error = ugen_fs_copy_out(f, pd->ep_index);
+ break;
+ }
+
+ case USB_FS_START:{
+ struct usb2_fs_start *pd = addr;
+
+ error = ugen_fs_copy_in(f, pd->ep_index);
+ if (error) {
+ break;
+ }
+ mtx_lock(f->priv_mtx);
+ usb2_transfer_start(f->fs_xfer[pd->ep_index]);
+ mtx_lock(f->priv_mtx);
+ break;
+ }
+ case USB_FS_STOP:{
+ struct usb2_fs_stop *pd = addr;
+
+ if (pd->ep_index >= f->fs_ep_max) {
+ error = EINVAL;
+ break;
+ }
+ mtx_lock(f->priv_mtx);
+ usb2_transfer_stop(f->fs_xfer[pd->ep_index]);
+ mtx_unlock(f->priv_mtx);
+ break;
+ }
+ case USB_FS_INIT:{
+ struct usb2_fs_init *pd = addr;
+
+ /* verify input parameters */
+ if (pd->pEndpoints == NULL) {
+ error = EINVAL;
+ break;
+ }
+ if (pd->ep_index_max > 127) {
+ error = EINVAL;
+ break;
+ }
+ if (pd->ep_index_max == 0) {
+ error = EINVAL;
+ break;
+ }
+ if (f->fs_xfer != NULL) {
+ error = EBUSY;
+ break;
+ }
+ if (f->dev_ep_index != 0) {
+ error = EINVAL;
+ break;
+ }
+ if (ugen_fifo_in_use(f, fflags)) {
+ error = EBUSY;
+ break;
+ }
+ error = usb2_fifo_alloc_buffer(f, 1, pd->ep_index_max);
+ if (error) {
+ break;
+ }
+ f->fs_xfer = malloc(sizeof(f->fs_xfer[0]) *
+ pd->ep_index_max, M_USB, M_WAITOK | M_ZERO);
+ if (f->fs_xfer == NULL) {
+ usb2_fifo_free_buffer(f);
+ error = ENOMEM;
+ break;
+ }
+ f->fs_ep_max = pd->ep_index_max;
+ f->fs_ep_ptr = pd->pEndpoints;
+ f->flag_no_uref = 1; /* drop locks we don't need */
+ break;
+ }
+
+ case USB_FS_UNINIT:{
+ struct usb2_fs_uninit *pd = addr;
+
+ if (pd->dummy != 0) {
+ error = EINVAL;
+ break;
+ }
+ error = ugen_fs_uninit(f);
+ if (error == 0) {
+ f->flag_no_uref = 0; /* restore operation */
+ }
+ break;
+ }
+
+ case USB_FS_OPEN:{
+ struct usb2_config usb2_config[1];
+ struct usb2_fs_open *pd = addr;
+ struct usb2_pipe *pipe;
+ struct usb2_endpoint_descriptor *ed;
+ uint8_t iface_index;
+ uint8_t isread;
+
+ if (pd->ep_index >= f->fs_ep_max) {
+ error = EINVAL;
+ break;
+ }
+ if (f->fs_xfer[pd->ep_index] != NULL) {
+ error = EBUSY;
+ break;
+ }
+ if (pd->max_bufsize > USB_FS_MAX_BUFSIZE) {
+ error = EINVAL;
+ break;
+ }
+ if (pd->max_frames > USB_FS_MAX_FRAMES) {
+ error = EINVAL;
+ break;
+ }
+ if (pd->max_frames == 0) {
+ error = EINVAL;
+ break;
+ }
+ pipe = usb2_get_pipe_by_addr(f->udev, pd->ep_no);
+ if (pipe == NULL) {
+ error = EINVAL;
+ break;
+ }
+ ed = pipe->edesc;
+ if (ed == NULL) {
+ error = ENXIO;
+ break;
+ }
+ iface_index = pipe->iface_index;
+
+ error = usb2_check_thread_perm(f->udev, curthread, fflags,
+ iface_index, pd->ep_no);
+ if (error) {
+ break;
+ }
+ bzero(usb2_config, sizeof(usb2_config));
+
+ usb2_config[0].type = ed->bmAttributes & UE_XFERTYPE;
+ usb2_config[0].endpoint = ed->bEndpointAddress & UE_ADDR;
+ usb2_config[0].direction = ed->bEndpointAddress & (UE_DIR_OUT | UE_DIR_IN);
+ usb2_config[0].mh.interval = USB_DEFAULT_INTERVAL;
+ usb2_config[0].mh.flags.proxy_buffer = 1;
+ usb2_config[0].mh.callback = &ugen_default_fs_callback;
+ usb2_config[0].mh.timeout = 0; /* no timeout */
+ usb2_config[0].mh.frames = pd->max_frames;
+ usb2_config[0].mh.bufsize = pd->max_bufsize;
+ usb2_config[0].md = usb2_config[0].mh; /* symmetric config */
+
+ if (usb2_config[0].type == UE_CONTROL) {
+ if (f->udev->flags.usb2_mode != USB_MODE_HOST) {
+ error = EINVAL;
+ break;
+ }
+ } else {
+
+ isread = ((usb2_config[0].endpoint &
+ (UE_DIR_IN | UE_DIR_OUT)) == UE_DIR_IN);
+
+ if (f->udev->flags.usb2_mode != USB_MODE_HOST) {
+ isread = !isread;
+ }
+ /* check permissions */
+ if (isread) {
+ if (!(fflags & FREAD)) {
+ error = EPERM;
+ break;
+ }
+ } else {
+ if (!(fflags & FWRITE)) {
+ error = EPERM;
+ break;
+ }
+ }
+ }
+ error = usb2_transfer_setup(f->udev, &iface_index,
+ f->fs_xfer + pd->ep_index, usb2_config, 1,
+ f, f->priv_mtx);
+ if (error == 0) {
+ /* update maximum buffer size */
+ pd->max_bufsize =
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list