USB: OHCI: DA8xx/OMAP-L1x glue layer
[safe/jmp/linux-2.6] / drivers / firewire / core-cdev.c
index c5f63a9..4eeaed5 100644 (file)
@@ -33,7 +33,9 @@
 #include <linux/mutex.h>
 #include <linux/poll.h>
 #include <linux/preempt.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/string.h>
 #include <linux/time.h>
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
@@ -178,7 +180,7 @@ struct iso_interrupt_event {
 
 struct iso_resource_event {
        struct event event;
-       struct fw_cdev_event_iso_resource resource;
+       struct fw_cdev_event_iso_resource iso_resource;
 };
 
 static inline void __user *u64_to_uptr(__u64 value)
@@ -435,26 +437,26 @@ static int add_client_resource(struct client *client,
 
 static int release_client_resource(struct client *client, u32 handle,
                                   client_resource_release_fn_t release,
-                                  struct client_resource **resource)
+                                  struct client_resource **return_resource)
 {
-       struct client_resource *r;
+       struct client_resource *resource;
 
        spin_lock_irq(&client->lock);
        if (client->in_shutdown)
-               r = NULL;
+               resource = NULL;
        else
-               r = idr_find(&client->resource_idr, handle);
-       if (r && r->release == release)
+               resource = idr_find(&client->resource_idr, handle);
+       if (resource && resource->release == release)
                idr_remove(&client->resource_idr, handle);
        spin_unlock_irq(&client->lock);
 
-       if (!(r && r->release == release))
+       if (!(resource && resource->release == release))
                return -EINVAL;
 
-       if (resource)
-               *resource = r;
+       if (return_resource)
+               *return_resource = resource;
        else
-               r->release(client, r);
+               resource->release(client, resource);
 
        client_put(client);
 
@@ -594,14 +596,22 @@ static int ioctl_send_request(struct client *client, void *buffer)
                            client->device->max_speed);
 }
 
+static inline bool is_fcp_request(struct fw_request *request)
+{
+       return request == NULL;
+}
+
 static void release_request(struct client *client,
                            struct client_resource *resource)
 {
        struct inbound_transaction_resource *r = container_of(resource,
                        struct inbound_transaction_resource, resource);
 
-       fw_send_response(client->device->card, r->request,
-                        RCODE_CONFLICT_ERROR);
+       if (is_fcp_request(r->request))
+               kfree(r->data);
+       else
+               fw_send_response(client->device->card, r->request,
+                                RCODE_CONFLICT_ERROR);
        kfree(r);
 }
 
@@ -614,6 +624,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
        struct address_handler_resource *handler = callback_data;
        struct inbound_transaction_resource *r;
        struct inbound_transaction_event *e;
+       void *fcp_frame = NULL;
        int ret;
 
        r = kmalloc(sizeof(*r), GFP_ATOMIC);
@@ -625,6 +636,18 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
        r->data    = payload;
        r->length  = length;
 
+       if (is_fcp_request(request)) {
+               /*
+                * FIXME: Let core-transaction.c manage a
+                * single reference-counted copy?
+                */
+               fcp_frame = kmemdup(payload, length, GFP_ATOMIC);
+               if (fcp_frame == NULL)
+                       goto failed;
+
+               r->data = fcp_frame;
+       }
+
        r->resource.release = release_request;
        ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
        if (ret < 0)
@@ -638,13 +661,16 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
        e->request.closure = handler->closure;
 
        queue_event(handler->client, &e->event,
-                   &e->request, sizeof(e->request), payload, length);
+                   &e->request, sizeof(e->request), r->data, length);
        return;
 
  failed:
        kfree(r);
        kfree(e);
-       fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+       kfree(fcp_frame);
+
+       if (!is_fcp_request(request))
+               fw_send_response(card, request, RCODE_CONFLICT_ERROR);
 }
 
 static void release_address_handler(struct client *client,
@@ -714,14 +740,16 @@ static int ioctl_send_response(struct client *client, void *buffer)
 
        r = container_of(resource, struct inbound_transaction_resource,
                         resource);
+       if (is_fcp_request(r->request))
+               goto out;
+
        if (request->length < r->length)
                r->length = request->length;
-
        if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
                ret = -EFAULT;
+               kfree(r->request);
                goto out;
        }
-
        fw_send_response(client->device->card, r->request, request->rcode);
  out:
        kfree(r);
@@ -1108,12 +1136,12 @@ static void iso_resource_work(struct work_struct *work)
                e = r->e_dealloc;
                r->e_dealloc = NULL;
        }
-       e->resource.handle      = r->resource.handle;
-       e->resource.channel     = channel;
-       e->resource.bandwidth   = bandwidth;
+       e->iso_resource.handle    = r->resource.handle;
+       e->iso_resource.channel   = channel;
+       e->iso_resource.bandwidth = bandwidth;
 
        queue_event(client, &e->event,
-                   &e->resource, sizeof(e->resource), NULL, 0);
+                   &e->iso_resource, sizeof(e->iso_resource), NULL, 0);
 
        if (free) {
                cancel_delayed_work(&r->work);
@@ -1166,10 +1194,10 @@ static int init_iso_resource(struct client *client,
        r->e_alloc      = e1;
        r->e_dealloc    = e2;
 
-       e1->resource.closure    = request->closure;
-       e1->resource.type       = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
-       e2->resource.closure    = request->closure;
-       e2->resource.type       = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
+       e1->iso_resource.closure = request->closure;
+       e1->iso_resource.type    = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
+       e2->iso_resource.closure = request->closure;
+       e2->iso_resource.type    = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
 
        if (todo == ISO_RES_ALLOC) {
                r->resource.release = release_iso_resource;
@@ -1299,7 +1327,23 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
 static int dispatch_ioctl(struct client *client,
                          unsigned int cmd, void __user *arg)
 {
-       char buffer[256];
+       char buffer[sizeof(union {
+               struct fw_cdev_get_info                 _00;
+               struct fw_cdev_send_request             _01;
+               struct fw_cdev_allocate                 _02;
+               struct fw_cdev_deallocate               _03;
+               struct fw_cdev_send_response            _04;
+               struct fw_cdev_initiate_bus_reset       _05;
+               struct fw_cdev_add_descriptor           _06;
+               struct fw_cdev_remove_descriptor        _07;
+               struct fw_cdev_create_iso_context       _08;
+               struct fw_cdev_queue_iso                _09;
+               struct fw_cdev_start_iso                _0a;
+               struct fw_cdev_stop_iso                 _0b;
+               struct fw_cdev_get_cycle_timer          _0c;
+               struct fw_cdev_allocate_iso_resource    _0d;
+               struct fw_cdev_send_stream_packet       _13;
+       })];
        int ret;
 
        if (_IOC_TYPE(cmd) != '#' ||
@@ -1394,10 +1438,10 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
 
 static int shutdown_resource(int id, void *p, void *data)
 {
-       struct client_resource *r = p;
+       struct client_resource *resource = p;
        struct client *client = data;
 
-       r->release(client, r);
+       resource->release(client, resource);
        client_put(client);
 
        return 0;
@@ -1406,7 +1450,7 @@ static int shutdown_resource(int id, void *p, void *data)
 static int fw_device_op_release(struct inode *inode, struct file *file)
 {
        struct client *client = file->private_data;
-       struct event *e, *next_e;
+       struct event *event, *next_event;
 
        mutex_lock(&client->device->client_list_mutex);
        list_del(&client->link);
@@ -1427,8 +1471,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
        idr_remove_all(&client->resource_idr);
        idr_destroy(&client->resource_idr);
 
-       list_for_each_entry_safe(e, next_e, &client->event_list, link)
-               kfree(e);
+       list_for_each_entry_safe(event, next_event, &client->event_list, link)
+               kfree(event);
 
        client_put(client);