Skip to content

Commit

Permalink
1.3.0 Release (May 2018)
Browse files Browse the repository at this point in the history
  • Loading branch information
katieensign committed Apr 1, 2018
1 parent f0f9427 commit ac1599d
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 48 deletions.
4 changes: 3 additions & 1 deletion u3v.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ struct u3v_device_info {
u32 transfer_alignment;
u32 segmented_xfer_supported;
u32 segmented_xfer_enabled;
u32 legacy_ctrl_ep_stall_enabled;
};

/* Helper functions for interfaces */
Expand Down Expand Up @@ -155,7 +156,8 @@ static inline struct u3v_device *u3v_get_driver_data(struct device *dev)
static inline bool hcd_is_xhci(struct usb_device *udev)
{
const char *hcd = bus_to_hcd(udev->bus)->driver->description;
return (strncmp(hcd, "xhci_hcd", 8) == 0);
return (strncmp(hcd, "xhci_hcd", 8) == 0 ||
strncmp(hcd, "xhci-hcd", 8) == 0);
}

#define GET_INTERFACE(ptr_type, ptr, interface_info) \
Expand Down
10 changes: 4 additions & 6 deletions u3v_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ int u3v_create_control(struct u3v_device *u3v)
goto error;
}

if (!u3v->stalling_disabled)
if (!u3v->stalling_disabled &&
u3v->u3v_info->legacy_ctrl_ep_stall_enabled)
reset_pipe(u3v, &u3v->control_info);

/*
Expand Down Expand Up @@ -194,7 +195,8 @@ void u3v_destroy_control(struct u3v_device *u3v)

wait_for_completion(&u3v->control_info.ioctl_complete);

if (!u3v->stalling_disabled)
if (!u3v->stalling_disabled &&
u3v->u3v_info->legacy_ctrl_ep_stall_enabled)
reset_pipe(u3v, &u3v->control_info);

kfree(ctrl->ack_buffer);
Expand Down Expand Up @@ -365,8 +367,6 @@ int u3v_read_memory(struct u3v_control *ctrl, u32 transfer_size,
dev_err(dev,
"%s: received an invalid READMEM_ACK buffer\n",
__func__);
dev_err(dev, "\tReceived bytes = %d, expected %zu\n",
actual, ack_buffer_size);
dev_err(dev, "\tPrefix = 0x%X, expected 0x%X\n",
ack->header.prefix, U3V_CONTROL_PREFIX);
dev_err(dev, "\tCmd = 0x%X, expected 0x%X or 0x%X\n",
Expand Down Expand Up @@ -600,8 +600,6 @@ int u3v_write_memory(struct u3v_control *ctrl, u32 transfer_size,
dev_err(dev,
"%s: received an invalid WRITEMEM_ACK buffer\n",
__func__);
dev_err(dev, "\tReceived bytes = %d, expected %zu\n",
actual, ack_buffer_size);
dev_err(dev, "\tPrefix = 0x%X, expected 0x%X\n",
ack->header.prefix, U3V_CONTROL_PREFIX);
dev_err(dev, "\tCmd = 0x%X, expected 0x%X or 0x%X\n",
Expand Down
52 changes: 34 additions & 18 deletions u3v_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ static ssize_t name##_store(struct device *dev, \
\
return count; \
} \
static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, name##_show, name##_store);
static DEVICE_ATTR(name, S_IWUSR | S_IWGRP | S_IRUGO, \
name##_show, name##_store);

#define u3v_attribute_str(name) \
static ssize_t name##_show(struct device *dev, \
Expand Down Expand Up @@ -198,6 +199,7 @@ u3v_attribute_num(host_byte_alignment);
u3v_attribute_num(os_max_transfer_size);
u3v_attribute_num(segmented_xfer_supported);
u3v_attribute_num_rw(segmented_xfer_enabled);
u3v_attribute_num_rw(legacy_ctrl_ep_stall_enabled);

static struct attribute *u3v_attrs[] = {
&dev_attr_idVendor.attr,
Expand All @@ -221,6 +223,7 @@ static struct attribute *u3v_attrs[] = {
&dev_attr_os_max_transfer_size.attr,
&dev_attr_segmented_xfer_supported.attr,
&dev_attr_segmented_xfer_enabled.attr,
&dev_attr_legacy_ctrl_ep_stall_enabled.attr,
NULL,
};

Expand Down Expand Up @@ -1281,17 +1284,32 @@ static int populate_u3v_properties(struct u3v_device *u3v)
usb_device_no_sg_constraint(u3v->udev);
#endif
/*
* this feature is currently experimental, so it is disabled
* This feature is currently experimental, so it is disabled
* by default
*/
u3v_info->segmented_xfer_enabled = 0;
return 0;
}


/*
* initialize_interface_management - this helper function initializes
* interface_info members required for interface management
* @info: pointer to a u3v_interface_info struct
*/
static void initialize_interface_management(struct u3v_interface_info *info)
{
info->ioctl_count = 0;
mutex_init(&info->interface_lock);
mutex_init(&info->ioctl_count_lock);
init_completion(&info->ioctl_complete);
complete_all(&info->ioctl_complete);
}


/*
* enumerate_u3v_interfaces - called by probe to claim the interfaces and
* store their endpoint information
* store their endpoint information
* @u3v - pointer to the u3v device struct
*/
static int enumerate_u3v_interfaces(struct u3v_device *u3v)
Expand Down Expand Up @@ -1327,11 +1345,6 @@ static int enumerate_u3v_interfaces(struct u3v_device *u3v)
find_bulk_endpoint(iface_desc, in);
u3v->control_info.bulk_out =
find_bulk_endpoint(iface_desc, out);
u3v->control_info.ioctl_count = 0;
mutex_init(&u3v->control_info.interface_lock);
mutex_init(&u3v->control_info.ioctl_count_lock);
init_completion(&u3v->control_info.ioctl_complete);
complete_all(&u3v->control_info.ioctl_complete);
break;
case U3V_INTERFACE_PROTOCOL_EVENT:
/* claim event interface */
Expand All @@ -1349,11 +1362,6 @@ static int enumerate_u3v_interfaces(struct u3v_device *u3v)
u3v->event_info.bulk_in =
find_bulk_endpoint(iface_desc, in);
u3v->event_info.bulk_out = NULL;
u3v->event_info.ioctl_count = 0;
mutex_init(&u3v->event_info.interface_lock);
mutex_init(&u3v->event_info.ioctl_count_lock);
init_completion(&u3v->event_info.ioctl_complete);
complete_all(&u3v->event_info.ioctl_complete);
break;
case U3V_INTERFACE_PROTOCOL_STREAM:
/* claim stream interface */
Expand All @@ -1371,11 +1379,6 @@ static int enumerate_u3v_interfaces(struct u3v_device *u3v)
u3v->stream_info.bulk_in =
find_bulk_endpoint(iface_desc, in);
u3v->stream_info.bulk_out = NULL;
u3v->stream_info.ioctl_count = 0;
mutex_init(&u3v->stream_info.interface_lock);
mutex_init(&u3v->stream_info.ioctl_count_lock);
init_completion(&u3v->stream_info.ioctl_complete);
complete_all(&u3v->stream_info.ioctl_complete);
break;
}
}
Expand Down Expand Up @@ -1433,6 +1436,19 @@ static int u3v_probe(struct usb_interface *interface,
ret = U3V_ERR_INVALID_USB_DESCRIPTOR;
goto error;
}
/*
* We unconditionally initialize the struct members related to
* interface management for the control, stream, and event
* channels. Regardless of whether the optional stream and
* event channels are supported, we need to keep track of
* ioctl calls per interface that are in flight. Guaranteeing
* that these members are initialized allows us to push the
* error-handling logic to the respective interface classes
* instead of the top level ioctls.
*/
initialize_interface_management(&u3v->control_info);
initialize_interface_management(&u3v->stream_info);
initialize_interface_management(&u3v->event_info);

ret = enumerate_u3v_interfaces(u3v);
if (ret < 0)
Expand Down
37 changes: 18 additions & 19 deletions u3v_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ int u3v_create_events(struct u3v_device *u3v, struct usb_interface *intf,
if (u3v->event_info.bulk_in == NULL) {
dev_err(u3v->device,
"%s: Did not detect bulk in endpoint in the event interface.\n",
__func__);
__func__);
return U3V_ERR_NO_EVENT_INTERFACE;
}

Expand Down Expand Up @@ -189,7 +189,7 @@ static int configure_events(struct u3v_event *event, u32 event_max_transfer,
}
unconfigure_events(event);
dev_err(event->u3v_dev->device,
"%s: Error allocating memory for event queue\n", __func__);
"%s: Error allocating memory for event queue\n", __func__);
return -ENOMEM;
}

Expand Down Expand Up @@ -359,7 +359,7 @@ static int queue_next_event(struct u3v_event *event)
}

entry = list_first_entry(&event->event_queue,
struct event_entry, list_elem);
struct event_entry, list_elem);

if (entry->state == event_queued) {
dev_err(event->u3v_dev->device,
Expand Down Expand Up @@ -417,10 +417,10 @@ static int submit_event_urb(struct u3v_event *event, struct event_entry *entry)
return 0;

usb_fill_bulk_urb(entry->purb, udev,
usb_rcvbulkpipe(udev,
usb_rcvbulkpipe(udev,
usb_endpoint_num(event->u3v_dev->event_info.bulk_in)),
entry->buffer, entry->buffer_size, event_urb_completion,
entry);
entry->buffer, entry->buffer_size, event_urb_completion,
entry);

usb_anchor_urb(entry->purb, &event->event_anchor);
ret = usb_submit_urb(entry->purb, GFP_KERNEL);
Expand Down Expand Up @@ -456,16 +456,15 @@ static void event_urb_completion(struct urb *purb)
purb->status == -ECONNRESET ||
purb->status == -ESHUTDOWN ||
purb->status == -EPROTO)) {
dev_err(dev,
"%s: Received nonzero urb completion status: %d",
dev_err(dev, "%s: Received nonzero urb completion status: %d",
__func__, purb->status);
}

entry = (struct event_entry *)(purb->context);
if (entry == NULL) {
dev_err(dev, "%s: Received a NULL context pointer\n",
__func__);
return;
__func__);
return;
}
/* Ensure buffer was queued */
WARN_ON(entry->state != event_queued);
Expand Down Expand Up @@ -521,7 +520,7 @@ int u3v_wait_for_event(struct u3v_event *event, void __user *u_buffer,
goto exit;
}
entry = list_first_entry(&event->event_queue,
struct event_entry, list_elem);
struct event_entry, list_elem);

/* Ensure that we are waiting on a queued event */
if (entry->state == event_idle) {
Expand Down Expand Up @@ -555,18 +554,18 @@ int u3v_wait_for_event(struct u3v_event *event, void __user *u_buffer,
/* check if we were interrupted by a signal */
if (ret != 0) {
dev_dbg(dev, "%s: wait interrupted by signal\n",
__func__);
__func__);
ret = U3V_ERR_EVENT_WAIT_CANCELED;
goto exit;
}

/* check if device was removed or wait cancelled somehow */
if (!event->u3v_dev->device_connected ||
!event->started ||
entry->callback_status == -ENOENT ||
entry->callback_status == -ECONNRESET ||
entry->callback_status == -ESHUTDOWN ||
entry->callback_status == -EPROTO) {
!event->started ||
entry->callback_status == -ENOENT ||
entry->callback_status == -ECONNRESET ||
entry->callback_status == -ESHUTDOWN ||
entry->callback_status == -EPROTO) {

dev_dbg(dev, "%s: Event interface was stopped\n",
__func__);
Expand All @@ -577,7 +576,7 @@ int u3v_wait_for_event(struct u3v_event *event, void __user *u_buffer,
/* Don't keep waiting if next event isn't queued */
if (entry->state == event_idle) {
dev_err(dev, "%s: Cannot wait on an unqueued entry\n",
__func__);
__func__);
ret = U3V_ERR_EVENTS_NOT_STARTED;
goto exit;
}
Expand Down Expand Up @@ -617,7 +616,7 @@ static int transfer_event_data(struct u3v_event *event, void __user *u_buffer,

dev = event->u3v_dev->device;
entry = list_first_entry(&event->event_queue,
struct event_entry, list_elem);
struct event_entry, list_elem);

/* Ensure we received a valid event command */
cmd = (struct command *)(entry->buffer);
Expand Down
35 changes: 31 additions & 4 deletions u3v_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <asm/unaligned.h>
#ifdef VERSION_COMPATIBILITY
#include <linux/version.h>
#else
#include <generated/uapi/linux/version.h>
#endif


/* Internal stream structs and enums */
Expand Down Expand Up @@ -1348,12 +1353,18 @@ static struct page **lock_user_pages(struct u3v_stream *stream,
down_read(&current->mm->mmap_sem);
/* will store a page locked array of physical pages in pages var */
ret = get_user_pages(
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
current,
current->mm,
#endif
uaddr,
num_pages,
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
WRITE,
0, /* Don't force */
#else
FOLL_WRITE,
#endif
pages,
NULL);
up_read(&current->mm->mmap_sem);
Expand Down Expand Up @@ -1495,10 +1506,26 @@ static int calculate_sglist_entries(struct u3v_stream *stream,
pg_idx, offset, limit);
if (bytes_to_transfer < 0)
return bytes_to_transfer;
if (stream->config.sg_constraint &&
(pglist_bytes_remaining > w_max_packet_size)) {
bytes_to_transfer = rounddown(bytes_to_transfer,
w_max_packet_size);
if (stream->config.sg_constraint) {
if (bytes_to_transfer > w_max_packet_size) {
bytes_to_transfer = rounddown(
bytes_to_transfer,
w_max_packet_size);
} else if (bytes_to_transfer < w_max_packet_size
&& !(sg_count == 0 ||
bytes_to_transfer ==
pglist_bytes_remaining)) {
/*
* if we're in the constraint case,
* the scatterlist can be unaligned
* with w_max_packet_size only if it's
* the first or last entry in the list
*/
dev_err(stream->u3v_dev->device,
"%s: invalid buffer: if sg_constraint is true, a buffer can only have a scatterlist entry smaller than w_max_packet_size if it's the first or last in the list\n",
__func__);
return U3V_ERR_INTERNAL;
}
}
segment_bytes_remaining -= bytes_to_transfer;
if (configure) {
Expand Down

0 comments on commit ac1599d

Please sign in to comment.