firewire: cdev: unify names of struct types and of their instances
to indicate that they are specializations of struct event or of struct client_resource, respectively. struct response was both an event and a client_resource; it is now split into struct outbound_transaction_resource and ~_event in order to document more explicitly which types of client resources exist. struct request and struct_request_event are renamed to struct inbound_transaction_resource and ~_event because requests and responses occur in outbound and in inbound transactions. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
@@ -41,43 +41,6 @@
|
|||||||
#include "fw-topology.h"
|
#include "fw-topology.h"
|
||||||
#include "fw-device.h"
|
#include "fw-device.h"
|
||||||
|
|
||||||
struct client;
|
|
||||||
struct client_resource;
|
|
||||||
typedef void (*client_resource_release_fn_t)(struct client *,
|
|
||||||
struct client_resource *);
|
|
||||||
struct client_resource {
|
|
||||||
client_resource_release_fn_t release;
|
|
||||||
int handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dequeue_event() just kfree()'s the event, so the event has to be
|
|
||||||
* the first field in the struct.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct event {
|
|
||||||
struct { void *data; size_t size; } v[2];
|
|
||||||
struct list_head link;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bus_reset {
|
|
||||||
struct event event;
|
|
||||||
struct fw_cdev_event_bus_reset reset;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct response {
|
|
||||||
struct event event;
|
|
||||||
struct fw_transaction transaction;
|
|
||||||
struct client *client;
|
|
||||||
struct client_resource resource;
|
|
||||||
struct fw_cdev_event_response response;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct iso_interrupt {
|
|
||||||
struct event event;
|
|
||||||
struct fw_cdev_event_iso_interrupt interrupt;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct client {
|
struct client {
|
||||||
u32 version;
|
u32 version;
|
||||||
struct fw_device *device;
|
struct fw_device *device;
|
||||||
@@ -116,6 +79,70 @@ static void client_put(struct client *client)
|
|||||||
kref_put(&client->kref, client_release);
|
kref_put(&client->kref, client_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct client_resource;
|
||||||
|
typedef void (*client_resource_release_fn_t)(struct client *,
|
||||||
|
struct client_resource *);
|
||||||
|
struct client_resource {
|
||||||
|
client_resource_release_fn_t release;
|
||||||
|
int handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct address_handler_resource {
|
||||||
|
struct client_resource resource;
|
||||||
|
struct fw_address_handler handler;
|
||||||
|
__u64 closure;
|
||||||
|
struct client *client;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct outbound_transaction_resource {
|
||||||
|
struct client_resource resource;
|
||||||
|
struct fw_transaction transaction;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct inbound_transaction_resource {
|
||||||
|
struct client_resource resource;
|
||||||
|
struct fw_request *request;
|
||||||
|
void *data;
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct descriptor_resource {
|
||||||
|
struct client_resource resource;
|
||||||
|
struct fw_descriptor descriptor;
|
||||||
|
u32 data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dequeue_event() just kfree()'s the event, so the event has to be
|
||||||
|
* the first field in a struct XYZ_event.
|
||||||
|
*/
|
||||||
|
struct event {
|
||||||
|
struct { void *data; size_t size; } v[2];
|
||||||
|
struct list_head link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bus_reset_event {
|
||||||
|
struct event event;
|
||||||
|
struct fw_cdev_event_bus_reset reset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct outbound_transaction_event {
|
||||||
|
struct event event;
|
||||||
|
struct client *client;
|
||||||
|
struct outbound_transaction_resource r;
|
||||||
|
struct fw_cdev_event_response response;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct inbound_transaction_event {
|
||||||
|
struct event event;
|
||||||
|
struct fw_cdev_event_request request;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iso_interrupt_event {
|
||||||
|
struct event event;
|
||||||
|
struct fw_cdev_event_iso_interrupt interrupt;
|
||||||
|
};
|
||||||
|
|
||||||
static inline void __user *u64_to_uptr(__u64 value)
|
static inline void __user *u64_to_uptr(__u64 value)
|
||||||
{
|
{
|
||||||
return (void __user *)(unsigned long)value;
|
return (void __user *)(unsigned long)value;
|
||||||
@@ -263,18 +290,18 @@ static void for_each_client(struct fw_device *device,
|
|||||||
|
|
||||||
static void queue_bus_reset_event(struct client *client)
|
static void queue_bus_reset_event(struct client *client)
|
||||||
{
|
{
|
||||||
struct bus_reset *bus_reset;
|
struct bus_reset_event *e;
|
||||||
|
|
||||||
bus_reset = kzalloc(sizeof(*bus_reset), GFP_KERNEL);
|
e = kzalloc(sizeof(*e), GFP_KERNEL);
|
||||||
if (bus_reset == NULL) {
|
if (e == NULL) {
|
||||||
fw_notify("Out of memory when allocating bus reset event\n");
|
fw_notify("Out of memory when allocating bus reset event\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fill_bus_reset_event(&bus_reset->reset, client);
|
fill_bus_reset_event(&e->reset, client);
|
||||||
|
|
||||||
queue_event(client, &bus_reset->event,
|
queue_event(client, &e->event,
|
||||||
&bus_reset->reset, sizeof(bus_reset->reset), NULL, 0);
|
&e->reset, sizeof(e->reset), NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fw_device_cdev_update(struct fw_device *device)
|
void fw_device_cdev_update(struct fw_device *device)
|
||||||
@@ -389,24 +416,24 @@ static int release_client_resource(struct client *client, u32 handle,
|
|||||||
static void release_transaction(struct client *client,
|
static void release_transaction(struct client *client,
|
||||||
struct client_resource *resource)
|
struct client_resource *resource)
|
||||||
{
|
{
|
||||||
struct response *response =
|
struct outbound_transaction_resource *r = container_of(resource,
|
||||||
container_of(resource, struct response, resource);
|
struct outbound_transaction_resource, resource);
|
||||||
|
|
||||||
fw_cancel_transaction(client->device->card, &response->transaction);
|
fw_cancel_transaction(client->device->card, &r->transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void complete_transaction(struct fw_card *card, int rcode,
|
static void complete_transaction(struct fw_card *card, int rcode,
|
||||||
void *payload, size_t length, void *data)
|
void *payload, size_t length, void *data)
|
||||||
{
|
{
|
||||||
struct response *response = data;
|
struct outbound_transaction_event *e = data;
|
||||||
struct client *client = response->client;
|
struct fw_cdev_event_response *rsp = &e->response;
|
||||||
|
struct client *client = e->client;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct fw_cdev_event_response *r = &response->response;
|
|
||||||
|
|
||||||
if (length < r->length)
|
if (length < rsp->length)
|
||||||
r->length = length;
|
rsp->length = length;
|
||||||
if (rcode == RCODE_COMPLETE)
|
if (rcode == RCODE_COMPLETE)
|
||||||
memcpy(r->data, payload, r->length);
|
memcpy(rsp->data, payload, rsp->length);
|
||||||
|
|
||||||
spin_lock_irqsave(&client->lock, flags);
|
spin_lock_irqsave(&client->lock, flags);
|
||||||
/*
|
/*
|
||||||
@@ -420,28 +447,28 @@ static void complete_transaction(struct fw_card *card, int rcode,
|
|||||||
* by release_client_resource and we must not drop it here.
|
* by release_client_resource and we must not drop it here.
|
||||||
*/
|
*/
|
||||||
if (!client->in_shutdown &&
|
if (!client->in_shutdown &&
|
||||||
idr_find(&client->resource_idr, response->resource.handle)) {
|
idr_find(&client->resource_idr, e->r.resource.handle)) {
|
||||||
idr_remove(&client->resource_idr, response->resource.handle);
|
idr_remove(&client->resource_idr, e->r.resource.handle);
|
||||||
/* Drop the idr's reference */
|
/* Drop the idr's reference */
|
||||||
client_put(client);
|
client_put(client);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&client->lock, flags);
|
spin_unlock_irqrestore(&client->lock, flags);
|
||||||
|
|
||||||
r->type = FW_CDEV_EVENT_RESPONSE;
|
rsp->type = FW_CDEV_EVENT_RESPONSE;
|
||||||
r->rcode = rcode;
|
rsp->rcode = rcode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the case that sizeof(*r) doesn't align with the position of the
|
* In the case that sizeof(*rsp) doesn't align with the position of the
|
||||||
* data, and the read is short, preserve an extra copy of the data
|
* data, and the read is short, preserve an extra copy of the data
|
||||||
* to stay compatible with a pre-2.6.27 bug. Since the bug is harmless
|
* to stay compatible with a pre-2.6.27 bug. Since the bug is harmless
|
||||||
* for short reads and some apps depended on it, this is both safe
|
* for short reads and some apps depended on it, this is both safe
|
||||||
* and prudent for compatibility.
|
* and prudent for compatibility.
|
||||||
*/
|
*/
|
||||||
if (r->length <= sizeof(*r) - offsetof(typeof(*r), data))
|
if (rsp->length <= sizeof(*rsp) - offsetof(typeof(*rsp), data))
|
||||||
queue_event(client, &response->event, r, sizeof(*r),
|
queue_event(client, &e->event, rsp, sizeof(*rsp),
|
||||||
r->data, r->length);
|
rsp->data, rsp->length);
|
||||||
else
|
else
|
||||||
queue_event(client, &response->event, r, sizeof(*r) + r->length,
|
queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
|
|
||||||
/* Drop the transaction callback's reference */
|
/* Drop the transaction callback's reference */
|
||||||
@@ -452,23 +479,23 @@ static int ioctl_send_request(struct client *client, void *buffer)
|
|||||||
{
|
{
|
||||||
struct fw_device *device = client->device;
|
struct fw_device *device = client->device;
|
||||||
struct fw_cdev_send_request *request = buffer;
|
struct fw_cdev_send_request *request = buffer;
|
||||||
struct response *response;
|
struct outbound_transaction_event *e;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* What is the biggest size we'll accept, really? */
|
/* What is the biggest size we'll accept, really? */
|
||||||
if (request->length > 4096)
|
if (request->length > 4096)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
response = kmalloc(sizeof(*response) + request->length, GFP_KERNEL);
|
e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL);
|
||||||
if (response == NULL)
|
if (e == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
response->client = client;
|
e->client = client;
|
||||||
response->response.length = request->length;
|
e->response.length = request->length;
|
||||||
response->response.closure = request->closure;
|
e->response.closure = request->closure;
|
||||||
|
|
||||||
if (request->data &&
|
if (request->data &&
|
||||||
copy_from_user(response->response.data,
|
copy_from_user(e->response.data,
|
||||||
u64_to_uptr(request->data), request->length)) {
|
u64_to_uptr(request->data), request->length)) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto failed;
|
goto failed;
|
||||||
@@ -492,86 +519,66 @@ static int ioctl_send_request(struct client *client, void *buffer)
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
response->resource.release = release_transaction;
|
e->r.resource.release = release_transaction;
|
||||||
ret = add_client_resource(client, &response->resource, GFP_KERNEL);
|
ret = add_client_resource(client, &e->r.resource, GFP_KERNEL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
/* Get a reference for the transaction callback */
|
/* Get a reference for the transaction callback */
|
||||||
client_get(client);
|
client_get(client);
|
||||||
|
|
||||||
fw_send_request(device->card, &response->transaction,
|
fw_send_request(device->card, &e->r.transaction,
|
||||||
request->tcode & 0x1f,
|
request->tcode & 0x1f,
|
||||||
device->node->node_id,
|
device->node->node_id,
|
||||||
request->generation,
|
request->generation,
|
||||||
device->max_speed,
|
device->max_speed,
|
||||||
request->offset,
|
request->offset,
|
||||||
response->response.data, request->length,
|
e->response.data, request->length,
|
||||||
complete_transaction, response);
|
complete_transaction, e);
|
||||||
|
|
||||||
if (request->data)
|
if (request->data)
|
||||||
return sizeof(request) + request->length;
|
return sizeof(request) + request->length;
|
||||||
else
|
else
|
||||||
return sizeof(request);
|
return sizeof(request);
|
||||||
failed:
|
failed:
|
||||||
kfree(response);
|
kfree(e);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct address_handler {
|
|
||||||
struct fw_address_handler handler;
|
|
||||||
__u64 closure;
|
|
||||||
struct client *client;
|
|
||||||
struct client_resource resource;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct request {
|
|
||||||
struct fw_request *request;
|
|
||||||
void *data;
|
|
||||||
size_t length;
|
|
||||||
struct client_resource resource;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct request_event {
|
|
||||||
struct event event;
|
|
||||||
struct fw_cdev_event_request request;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void release_request(struct client *client,
|
static void release_request(struct client *client,
|
||||||
struct client_resource *resource)
|
struct client_resource *resource)
|
||||||
{
|
{
|
||||||
struct request *request =
|
struct inbound_transaction_resource *r = container_of(resource,
|
||||||
container_of(resource, struct request, resource);
|
struct inbound_transaction_resource, resource);
|
||||||
|
|
||||||
fw_send_response(client->device->card, request->request,
|
fw_send_response(client->device->card, r->request,
|
||||||
RCODE_CONFLICT_ERROR);
|
RCODE_CONFLICT_ERROR);
|
||||||
kfree(request);
|
kfree(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_request(struct fw_card *card, struct fw_request *r,
|
static void handle_request(struct fw_card *card, struct fw_request *request,
|
||||||
int tcode, int destination, int source,
|
int tcode, int destination, int source,
|
||||||
int generation, int speed,
|
int generation, int speed,
|
||||||
unsigned long long offset,
|
unsigned long long offset,
|
||||||
void *payload, size_t length, void *callback_data)
|
void *payload, size_t length, void *callback_data)
|
||||||
{
|
{
|
||||||
struct address_handler *handler = callback_data;
|
struct address_handler_resource *handler = callback_data;
|
||||||
struct request *request;
|
struct inbound_transaction_resource *r;
|
||||||
struct request_event *e;
|
struct inbound_transaction_event *e;
|
||||||
struct client *client = handler->client;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
request = kmalloc(sizeof(*request), GFP_ATOMIC);
|
r = kmalloc(sizeof(*r), GFP_ATOMIC);
|
||||||
e = kmalloc(sizeof(*e), GFP_ATOMIC);
|
e = kmalloc(sizeof(*e), GFP_ATOMIC);
|
||||||
if (request == NULL || e == NULL)
|
if (r == NULL || e == NULL)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
request->request = r;
|
r->request = request;
|
||||||
request->data = payload;
|
r->data = payload;
|
||||||
request->length = length;
|
r->length = length;
|
||||||
|
|
||||||
request->resource.release = release_request;
|
r->resource.release = release_request;
|
||||||
ret = add_client_resource(client, &request->resource, GFP_ATOMIC);
|
ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
@@ -579,61 +586,61 @@ static void handle_request(struct fw_card *card, struct fw_request *r,
|
|||||||
e->request.tcode = tcode;
|
e->request.tcode = tcode;
|
||||||
e->request.offset = offset;
|
e->request.offset = offset;
|
||||||
e->request.length = length;
|
e->request.length = length;
|
||||||
e->request.handle = request->resource.handle;
|
e->request.handle = r->resource.handle;
|
||||||
e->request.closure = handler->closure;
|
e->request.closure = handler->closure;
|
||||||
|
|
||||||
queue_event(client, &e->event,
|
queue_event(handler->client, &e->event,
|
||||||
&e->request, sizeof(e->request), payload, length);
|
&e->request, sizeof(e->request), payload, length);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
kfree(request);
|
kfree(r);
|
||||||
kfree(e);
|
kfree(e);
|
||||||
fw_send_response(card, r, RCODE_CONFLICT_ERROR);
|
fw_send_response(card, request, RCODE_CONFLICT_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void release_address_handler(struct client *client,
|
static void release_address_handler(struct client *client,
|
||||||
struct client_resource *resource)
|
struct client_resource *resource)
|
||||||
{
|
{
|
||||||
struct address_handler *handler =
|
struct address_handler_resource *r =
|
||||||
container_of(resource, struct address_handler, resource);
|
container_of(resource, struct address_handler_resource, resource);
|
||||||
|
|
||||||
fw_core_remove_address_handler(&handler->handler);
|
fw_core_remove_address_handler(&r->handler);
|
||||||
kfree(handler);
|
kfree(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioctl_allocate(struct client *client, void *buffer)
|
static int ioctl_allocate(struct client *client, void *buffer)
|
||||||
{
|
{
|
||||||
struct fw_cdev_allocate *request = buffer;
|
struct fw_cdev_allocate *request = buffer;
|
||||||
struct address_handler *handler;
|
struct address_handler_resource *r;
|
||||||
struct fw_address_region region;
|
struct fw_address_region region;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
handler = kmalloc(sizeof(*handler), GFP_KERNEL);
|
r = kmalloc(sizeof(*r), GFP_KERNEL);
|
||||||
if (handler == NULL)
|
if (r == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
region.start = request->offset;
|
region.start = request->offset;
|
||||||
region.end = request->offset + request->length;
|
region.end = request->offset + request->length;
|
||||||
handler->handler.length = request->length;
|
r->handler.length = request->length;
|
||||||
handler->handler.address_callback = handle_request;
|
r->handler.address_callback = handle_request;
|
||||||
handler->handler.callback_data = handler;
|
r->handler.callback_data = r;
|
||||||
handler->closure = request->closure;
|
r->closure = request->closure;
|
||||||
handler->client = client;
|
r->client = client;
|
||||||
|
|
||||||
ret = fw_core_add_address_handler(&handler->handler, ®ion);
|
ret = fw_core_add_address_handler(&r->handler, ®ion);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
kfree(handler);
|
kfree(r);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler->resource.release = release_address_handler;
|
r->resource.release = release_address_handler;
|
||||||
ret = add_client_resource(client, &handler->resource, GFP_KERNEL);
|
ret = add_client_resource(client, &r->resource, GFP_KERNEL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
release_address_handler(client, &handler->resource);
|
release_address_handler(client, &r->resource);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
request->handle = handler->resource.handle;
|
request->handle = r->resource.handle;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -650,13 +657,14 @@ static int ioctl_send_response(struct client *client, void *buffer)
|
|||||||
{
|
{
|
||||||
struct fw_cdev_send_response *request = buffer;
|
struct fw_cdev_send_response *request = buffer;
|
||||||
struct client_resource *resource;
|
struct client_resource *resource;
|
||||||
struct request *r;
|
struct inbound_transaction_resource *r;
|
||||||
|
|
||||||
if (release_client_resource(client, request->handle,
|
if (release_client_resource(client, request->handle,
|
||||||
release_request, &resource) < 0)
|
release_request, &resource) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
r = container_of(resource, struct request, resource);
|
r = container_of(resource, struct inbound_transaction_resource,
|
||||||
|
resource);
|
||||||
if (request->length < r->length)
|
if (request->length < r->length)
|
||||||
r->length = request->length;
|
r->length = request->length;
|
||||||
if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
|
if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
|
||||||
@@ -678,62 +686,55 @@ static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
|
|||||||
return fw_core_initiate_bus_reset(client->device->card, short_reset);
|
return fw_core_initiate_bus_reset(client->device->card, short_reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct descriptor {
|
|
||||||
struct fw_descriptor d;
|
|
||||||
struct client_resource resource;
|
|
||||||
u32 data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void release_descriptor(struct client *client,
|
static void release_descriptor(struct client *client,
|
||||||
struct client_resource *resource)
|
struct client_resource *resource)
|
||||||
{
|
{
|
||||||
struct descriptor *descriptor =
|
struct descriptor_resource *r =
|
||||||
container_of(resource, struct descriptor, resource);
|
container_of(resource, struct descriptor_resource, resource);
|
||||||
|
|
||||||
fw_core_remove_descriptor(&descriptor->d);
|
fw_core_remove_descriptor(&r->descriptor);
|
||||||
kfree(descriptor);
|
kfree(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioctl_add_descriptor(struct client *client, void *buffer)
|
static int ioctl_add_descriptor(struct client *client, void *buffer)
|
||||||
{
|
{
|
||||||
struct fw_cdev_add_descriptor *request = buffer;
|
struct fw_cdev_add_descriptor *request = buffer;
|
||||||
struct descriptor *descriptor;
|
struct descriptor_resource *r;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (request->length > 256)
|
if (request->length > 256)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
descriptor =
|
r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL);
|
||||||
kmalloc(sizeof(*descriptor) + request->length * 4, GFP_KERNEL);
|
if (r == NULL)
|
||||||
if (descriptor == NULL)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (copy_from_user(descriptor->data,
|
if (copy_from_user(r->data,
|
||||||
u64_to_uptr(request->data), request->length * 4)) {
|
u64_to_uptr(request->data), request->length * 4)) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor->d.length = request->length;
|
r->descriptor.length = request->length;
|
||||||
descriptor->d.immediate = request->immediate;
|
r->descriptor.immediate = request->immediate;
|
||||||
descriptor->d.key = request->key;
|
r->descriptor.key = request->key;
|
||||||
descriptor->d.data = descriptor->data;
|
r->descriptor.data = r->data;
|
||||||
|
|
||||||
ret = fw_core_add_descriptor(&descriptor->d);
|
ret = fw_core_add_descriptor(&r->descriptor);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
descriptor->resource.release = release_descriptor;
|
r->resource.release = release_descriptor;
|
||||||
ret = add_client_resource(client, &descriptor->resource, GFP_KERNEL);
|
ret = add_client_resource(client, &r->resource, GFP_KERNEL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fw_core_remove_descriptor(&descriptor->d);
|
fw_core_remove_descriptor(&r->descriptor);
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
request->handle = descriptor->resource.handle;
|
request->handle = r->resource.handle;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
failed:
|
failed:
|
||||||
kfree(descriptor);
|
kfree(r);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -750,19 +751,19 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle,
|
|||||||
size_t header_length, void *header, void *data)
|
size_t header_length, void *header, void *data)
|
||||||
{
|
{
|
||||||
struct client *client = data;
|
struct client *client = data;
|
||||||
struct iso_interrupt *irq;
|
struct iso_interrupt_event *e;
|
||||||
|
|
||||||
irq = kzalloc(sizeof(*irq) + header_length, GFP_ATOMIC);
|
e = kzalloc(sizeof(*e) + header_length, GFP_ATOMIC);
|
||||||
if (irq == NULL)
|
if (e == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
irq->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
|
e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
|
||||||
irq->interrupt.closure = client->iso_closure;
|
e->interrupt.closure = client->iso_closure;
|
||||||
irq->interrupt.cycle = cycle;
|
e->interrupt.cycle = cycle;
|
||||||
irq->interrupt.header_length = header_length;
|
e->interrupt.header_length = header_length;
|
||||||
memcpy(irq->interrupt.header, header, header_length);
|
memcpy(e->interrupt.header, header, header_length);
|
||||||
queue_event(client, &irq->event, &irq->interrupt,
|
queue_event(client, &e->event, &e->interrupt,
|
||||||
sizeof(irq->interrupt) + header_length, NULL, 0);
|
sizeof(e->interrupt) + header_length, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioctl_create_iso_context(struct client *client, void *buffer)
|
static int ioctl_create_iso_context(struct client *client, void *buffer)
|
||||||
|
Reference in New Issue
Block a user