]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/firewire/fw-cdev.c
spi: limit reaches -1, tested 0
[linux-2.6-omap-h63xx.git] / drivers / firewire / fw-cdev.c
index 3d816a6395cd2c575b33db3023b133fef4e557df..7eb6594cc3e5b92e9891773ada1898a4f0831c38 100644 (file)
@@ -129,7 +129,7 @@ struct iso_resource {
        struct iso_resource_event *e_alloc, *e_dealloc;
 };
 
-static int schedule_iso_resource(struct iso_resource *);
+static void schedule_iso_resource(struct iso_resource *);
 static void release_iso_resource(struct client *, struct client_resource *);
 
 /*
@@ -522,7 +522,8 @@ static int init_request(struct client *client,
        struct outbound_transaction_event *e;
        int ret;
 
-       if (request->length > 4096 || request->length > 512 << speed)
+       if (request->tcode != TCODE_STREAM_DATA &&
+           (request->length > 4096 || request->length > 512 << speed))
                return -EIO;
 
        e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL);
@@ -549,15 +550,11 @@ static int init_request(struct client *client,
        client_get(client);
 
        fw_send_request(client->device->card, &e->r.transaction,
-                       request->tcode & 0x1f, destination_id,
-                       request->generation, speed, request->offset,
-                       e->response.data, request->length,
-                       complete_transaction, e);
+                       request->tcode, destination_id, request->generation,
+                       speed, request->offset, e->response.data,
+                       request->length, complete_transaction, e);
+       return 0;
 
-       if (request->data)
-               return sizeof(request) + request->length;
-       else
-               return sizeof(request);
  failed:
        kfree(e);
 
@@ -585,7 +582,7 @@ static int ioctl_send_request(struct client *client, void *buffer)
                return -EINVAL;
        }
 
-       return init_request(client, request, client->device->node->node_id,
+       return init_request(client, request, client->device->node_id,
                            client->device->max_speed);
 }
 
@@ -742,9 +739,17 @@ static void release_descriptor(struct client *client,
 static int ioctl_add_descriptor(struct client *client, void *buffer)
 {
        struct fw_cdev_add_descriptor *request = buffer;
+       struct fw_card *card = client->device->card;
        struct descriptor_resource *r;
        int ret;
 
+       /* Access policy: Allow this ioctl only on local nodes' device files. */
+       spin_lock_irq(&card->lock);
+       ret = client->device->node_id != card->local_node->node_id;
+       spin_unlock_irq(&card->lock);
+       if (ret)
+               return -ENOSYS;
+
        if (request->length > 256)
                return -EINVAL;
 
@@ -1082,7 +1087,7 @@ static void iso_resource_work(struct work_struct *work)
        spin_unlock_irq(&client->lock);
 
        if (todo == ISO_RES_ALLOC && channel >= 0)
-               r->channels = 1ULL << (63 - channel);
+               r->channels = 1ULL << channel;
 
        if (todo == ISO_RES_REALLOC && success)
                goto out;
@@ -1111,17 +1116,11 @@ static void iso_resource_work(struct work_struct *work)
        client_put(client);
 }
 
-static int schedule_iso_resource(struct iso_resource *r)
+static void schedule_iso_resource(struct iso_resource *r)
 {
-       int scheduled;
-
        client_get(r->client);
-
-       scheduled = schedule_delayed_work(&r->work, 0);
-       if (!scheduled)
+       if (!schedule_delayed_work(&r->work, 0))
                client_put(r->client);
-
-       return scheduled;
 }
 
 static void release_iso_resource(struct client *client,
@@ -1173,13 +1172,13 @@ static int init_iso_resource(struct client *client,
        if (todo == ISO_RES_ALLOC) {
                r->resource.release = release_iso_resource;
                ret = add_client_resource(client, &r->resource, GFP_KERNEL);
+               if (ret < 0)
+                       goto fail;
        } else {
                r->resource.release = NULL;
                r->resource.handle = -1;
-               ret = schedule_iso_resource(r) ? 0 : -ENOMEM;
+               schedule_iso_resource(r);
        }
-       if (ret < 0)
-               goto fail;
        request->handle = r->resource.handle;
 
        return 0;
@@ -1220,13 +1219,14 @@ static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffe
        return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE);
 }
 
+/*
+ * Returns a speed code:  Maximum speed to or from this device,
+ * limited by the device's link speed, the local node's link speed,
+ * and all PHY port speeds between the two links.
+ */
 static int ioctl_get_speed(struct client *client, void *buffer)
 {
-       struct fw_cdev_get_speed *request = buffer;
-
-       request->max_speed = client->device->max_speed;
-
-       return 0;
+       return client->device->max_speed;
 }
 
 static int ioctl_send_broadcast_request(struct client *client, void *buffer)
@@ -1248,6 +1248,29 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer)
        return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100);
 }
 
+static int ioctl_send_stream_packet(struct client *client, void *buffer)
+{
+       struct fw_cdev_send_stream_packet *p = buffer;
+       struct fw_cdev_send_request request;
+       int dest;
+
+       if (p->speed > client->device->card->link_speed ||
+           p->length > 1024 << p->speed)
+               return -EIO;
+
+       if (p->tag > 3 || p->channel > 63 || p->sy > 15)
+               return -EINVAL;
+
+       dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy);
+       request.tcode           = TCODE_STREAM_DATA;
+       request.length          = p->length;
+       request.closure         = p->closure;
+       request.data            = p->data;
+       request.generation      = p->generation;
+
+       return init_request(client, &request, dest, p->speed);
+}
+
 static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
        ioctl_get_info,
        ioctl_send_request,
@@ -1268,6 +1291,7 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
        ioctl_deallocate_iso_resource_once,
        ioctl_get_speed,
        ioctl_send_broadcast_request,
+       ioctl_send_stream_packet,
 };
 
 static int dispatch_ioctl(struct client *client,
@@ -1386,12 +1410,12 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
        list_del(&client->link);
        mutex_unlock(&client->device->client_list_mutex);
 
-       if (client->buffer.pages)
-               fw_iso_buffer_destroy(&client->buffer, client->device->card);
-
        if (client->iso_context)
                fw_iso_context_destroy(client->iso_context);
 
+       if (client->buffer.pages)
+               fw_iso_buffer_destroy(&client->buffer, client->device->card);
+
        /* Freeze client->resource_idr and client->event_list */
        spin_lock_irq(&client->lock);
        client->in_shutdown = true;