Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Mar 2010 16:08:44 +0000 (08:08 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Mar 2010 16:08:44 +0000 (08:08 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: (23 commits)
  firewire: ohci: extend initialization log message
  firewire: ohci: fix IR/IT context mask mixup
  firewire: ohci: add module parameter to activate quirk fixes
  firewire: ohci: use an ID table for quirks detection
  firewire: ohci: reorder struct fw_ohci for better cache efficiency
  firewire: ohci: remove unused dualbuffer IR code
  firewire: core: combine a bit of repeated code
  firewire: core: change type of a data buffer
  firewire: cdev: increment ABI version number
  firewire: cdev: add more flexible cycle timer ioctl
  firewire: core: rename an internal function
  firewire: core: fix an information leak
  firewire: core: increase stack size of config ROM reader
  firewire: core: don't fail device creation in case of too large config ROM blocks
  firewire: core: fix "giving up on config rom" with Panasonic AG-DV2500
  firewire: remove incomplete Bus_Time CSR support
  firewire: get_cycle_timer optimization and cleanup
  firewire: ohci: enable cycle timer fix on ALi and NEC controllers
  firewire: ohci: work around cycle timer bugs on VIA controllers
  firewire: make PCI device id constant
  ...

drivers/firewire/core-cdev.c
drivers/firewire/core-device.c
drivers/firewire/core-transaction.c
drivers/firewire/core.h
drivers/firewire/ohci.c
drivers/firewire/sbp2.c
drivers/media/dvb/firewire/firedtv-fw.c
include/linux/firewire-cdev.h
include/linux/firewire.h
include/linux/pci_ids.h

index 4eeaed57e2197a0dd5f0cab7cffa4713eaf2ec96..8be720b278b7a435d2c106794c2cd663438c92a7 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/firewire.h>
 #include <linux/firewire-cdev.h>
 #include <linux/idr.h>
+#include <linux/irqflags.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/kref.h>
@@ -32,7 +33,6 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
-#include <linux/preempt.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -368,39 +368,56 @@ void fw_device_cdev_remove(struct fw_device *device)
        for_each_client(device, wake_up_client);
 }
 
-static int ioctl_get_info(struct client *client, void *buffer)
+union ioctl_arg {
+       struct fw_cdev_get_info                 get_info;
+       struct fw_cdev_send_request             send_request;
+       struct fw_cdev_allocate                 allocate;
+       struct fw_cdev_deallocate               deallocate;
+       struct fw_cdev_send_response            send_response;
+       struct fw_cdev_initiate_bus_reset       initiate_bus_reset;
+       struct fw_cdev_add_descriptor           add_descriptor;
+       struct fw_cdev_remove_descriptor        remove_descriptor;
+       struct fw_cdev_create_iso_context       create_iso_context;
+       struct fw_cdev_queue_iso                queue_iso;
+       struct fw_cdev_start_iso                start_iso;
+       struct fw_cdev_stop_iso                 stop_iso;
+       struct fw_cdev_get_cycle_timer          get_cycle_timer;
+       struct fw_cdev_allocate_iso_resource    allocate_iso_resource;
+       struct fw_cdev_send_stream_packet       send_stream_packet;
+       struct fw_cdev_get_cycle_timer2         get_cycle_timer2;
+};
+
+static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_get_info *get_info = buffer;
+       struct fw_cdev_get_info *a = &arg->get_info;
        struct fw_cdev_event_bus_reset bus_reset;
        unsigned long ret = 0;
 
-       client->version = get_info->version;
-       get_info->version = FW_CDEV_VERSION;
-       get_info->card = client->device->card->index;
+       client->version = a->version;
+       a->version = FW_CDEV_VERSION;
+       a->card = client->device->card->index;
 
        down_read(&fw_device_rwsem);
 
-       if (get_info->rom != 0) {
-               void __user *uptr = u64_to_uptr(get_info->rom);
-               size_t want = get_info->rom_length;
+       if (a->rom != 0) {
+               size_t want = a->rom_length;
                size_t have = client->device->config_rom_length * 4;
 
-               ret = copy_to_user(uptr, client->device->config_rom,
-                                  min(want, have));
+               ret = copy_to_user(u64_to_uptr(a->rom),
+                                  client->device->config_rom, min(want, have));
        }
-       get_info->rom_length = client->device->config_rom_length * 4;
+       a->rom_length = client->device->config_rom_length * 4;
 
        up_read(&fw_device_rwsem);
 
        if (ret != 0)
                return -EFAULT;
 
-       client->bus_reset_closure = get_info->bus_reset_closure;
-       if (get_info->bus_reset != 0) {
-               void __user *uptr = u64_to_uptr(get_info->bus_reset);
-
+       client->bus_reset_closure = a->bus_reset_closure;
+       if (a->bus_reset != 0) {
                fill_bus_reset_event(&bus_reset, client);
-               if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
+               if (copy_to_user(u64_to_uptr(a->bus_reset),
+                                &bus_reset, sizeof(bus_reset)))
                        return -EFAULT;
        }
 
@@ -571,11 +588,9 @@ static int init_request(struct client *client,
        return ret;
 }
 
-static int ioctl_send_request(struct client *client, void *buffer)
+static int ioctl_send_request(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_send_request *request = buffer;
-
-       switch (request->tcode) {
+       switch (arg->send_request.tcode) {
        case TCODE_WRITE_QUADLET_REQUEST:
        case TCODE_WRITE_BLOCK_REQUEST:
        case TCODE_READ_QUADLET_REQUEST:
@@ -592,7 +607,7 @@ static int ioctl_send_request(struct client *client, void *buffer)
                return -EINVAL;
        }
 
-       return init_request(client, request, client->device->node_id,
+       return init_request(client, &arg->send_request, client->device->node_id,
                            client->device->max_speed);
 }
 
@@ -683,9 +698,9 @@ static void release_address_handler(struct client *client,
        kfree(r);
 }
 
-static int ioctl_allocate(struct client *client, void *buffer)
+static int ioctl_allocate(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_allocate *request = buffer;
+       struct fw_cdev_allocate *a = &arg->allocate;
        struct address_handler_resource *r;
        struct fw_address_region region;
        int ret;
@@ -694,13 +709,13 @@ static int ioctl_allocate(struct client *client, void *buffer)
        if (r == NULL)
                return -ENOMEM;
 
-       region.start = request->offset;
-       region.end = request->offset + request->length;
-       r->handler.length = request->length;
+       region.start = a->offset;
+       region.end   = a->offset + a->length;
+       r->handler.length           = a->length;
        r->handler.address_callback = handle_request;
-       r->handler.callback_data = r;
-       r->closure = request->closure;
-       r->client = client;
+       r->handler.callback_data    = r;
+       r->closure   = a->closure;
+       r->client    = client;
 
        ret = fw_core_add_address_handler(&r->handler, &region);
        if (ret < 0) {
@@ -714,27 +729,25 @@ static int ioctl_allocate(struct client *client, void *buffer)
                release_address_handler(client, &r->resource);
                return ret;
        }
-       request->handle = r->resource.handle;
+       a->handle = r->resource.handle;
 
        return 0;
 }
 
-static int ioctl_deallocate(struct client *client, void *buffer)
+static int ioctl_deallocate(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_deallocate *request = buffer;
-
-       return release_client_resource(client, request->handle,
+       return release_client_resource(client, arg->deallocate.handle,
                                       release_address_handler, NULL);
 }
 
-static int ioctl_send_response(struct client *client, void *buffer)
+static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_send_response *request = buffer;
+       struct fw_cdev_send_response *a = &arg->send_response;
        struct client_resource *resource;
        struct inbound_transaction_resource *r;
        int ret = 0;
 
-       if (release_client_resource(client, request->handle,
+       if (release_client_resource(client, a->handle,
                                    release_request, &resource) < 0)
                return -EINVAL;
 
@@ -743,28 +756,24 @@ static int ioctl_send_response(struct client *client, void *buffer)
        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)) {
+       if (a->length < r->length)
+               r->length = a->length;
+       if (copy_from_user(r->data, u64_to_uptr(a->data), r->length)) {
                ret = -EFAULT;
                kfree(r->request);
                goto out;
        }
-       fw_send_response(client->device->card, r->request, request->rcode);
+       fw_send_response(client->device->card, r->request, a->rcode);
  out:
        kfree(r);
 
        return ret;
 }
 
-static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
+static int ioctl_initiate_bus_reset(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_initiate_bus_reset *request = buffer;
-       int short_reset;
-
-       short_reset = (request->type == FW_CDEV_SHORT_RESET);
-
-       return fw_core_initiate_bus_reset(client->device->card, short_reset);
+       return fw_core_initiate_bus_reset(client->device->card,
+                       arg->initiate_bus_reset.type == FW_CDEV_SHORT_RESET);
 }
 
 static void release_descriptor(struct client *client,
@@ -777,9 +786,9 @@ static void release_descriptor(struct client *client,
        kfree(r);
 }
 
-static int ioctl_add_descriptor(struct client *client, void *buffer)
+static int ioctl_add_descriptor(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_add_descriptor *request = buffer;
+       struct fw_cdev_add_descriptor *a = &arg->add_descriptor;
        struct descriptor_resource *r;
        int ret;
 
@@ -787,22 +796,21 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
        if (!client->device->is_local)
                return -ENOSYS;
 
-       if (request->length > 256)
+       if (a->length > 256)
                return -EINVAL;
 
-       r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL);
+       r = kmalloc(sizeof(*r) + a->length * 4, GFP_KERNEL);
        if (r == NULL)
                return -ENOMEM;
 
-       if (copy_from_user(r->data,
-                          u64_to_uptr(request->data), request->length * 4)) {
+       if (copy_from_user(r->data, u64_to_uptr(a->data), a->length * 4)) {
                ret = -EFAULT;
                goto failed;
        }
 
-       r->descriptor.length    = request->length;
-       r->descriptor.immediate = request->immediate;
-       r->descriptor.key       = request->key;
+       r->descriptor.length    = a->length;
+       r->descriptor.immediate = a->immediate;
+       r->descriptor.key       = a->key;
        r->descriptor.data      = r->data;
 
        ret = fw_core_add_descriptor(&r->descriptor);
@@ -815,7 +823,7 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
                fw_core_remove_descriptor(&r->descriptor);
                goto failed;
        }
-       request->handle = r->resource.handle;
+       a->handle = r->resource.handle;
 
        return 0;
  failed:
@@ -824,11 +832,9 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
        return ret;
 }
 
-static int ioctl_remove_descriptor(struct client *client, void *buffer)
+static int ioctl_remove_descriptor(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_remove_descriptor *request = buffer;
-
-       return release_client_resource(client, request->handle,
+       return release_client_resource(client, arg->remove_descriptor.handle,
                                       release_descriptor, NULL);
 }
 
@@ -851,49 +857,44 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle,
                    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, union ioctl_arg *arg)
 {
-       struct fw_cdev_create_iso_context *request = buffer;
+       struct fw_cdev_create_iso_context *a = &arg->create_iso_context;
        struct fw_iso_context *context;
 
        /* We only support one context at this time. */
        if (client->iso_context != NULL)
                return -EBUSY;
 
-       if (request->channel > 63)
+       if (a->channel > 63)
                return -EINVAL;
 
-       switch (request->type) {
+       switch (a->type) {
        case FW_ISO_CONTEXT_RECEIVE:
-               if (request->header_size < 4 || (request->header_size & 3))
+               if (a->header_size < 4 || (a->header_size & 3))
                        return -EINVAL;
-
                break;
 
        case FW_ISO_CONTEXT_TRANSMIT:
-               if (request->speed > SCODE_3200)
+               if (a->speed > SCODE_3200)
                        return -EINVAL;
-
                break;
 
        default:
                return -EINVAL;
        }
 
-       context =  fw_iso_context_create(client->device->card,
-                                        request->type,
-                                        request->channel,
-                                        request->speed,
-                                        request->header_size,
-                                        iso_callback, client);
+       context = fw_iso_context_create(client->device->card, a->type,
+                                       a->channel, a->speed, a->header_size,
+                                       iso_callback, client);
        if (IS_ERR(context))
                return PTR_ERR(context);
 
-       client->iso_closure = request->closure;
+       client->iso_closure = a->closure;
        client->iso_context = context;
 
        /* We only support one context at this time. */
-       request->handle = 0;
+       a->handle = 0;
 
        return 0;
 }
@@ -906,9 +907,9 @@ static int ioctl_create_iso_context(struct client *client, void *buffer)
 #define GET_SY(v)              (((v) >> 20) & 0x0f)
 #define GET_HEADER_LENGTH(v)   (((v) >> 24) & 0xff)
 
-static int ioctl_queue_iso(struct client *client, void *buffer)
+static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_queue_iso *request = buffer;
+       struct fw_cdev_queue_iso *a = &arg->queue_iso;
        struct fw_cdev_iso_packet __user *p, *end, *next;
        struct fw_iso_context *ctx = client->iso_context;
        unsigned long payload, buffer_end, header_length;
@@ -919,7 +920,7 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
                u8 header[256];
        } u;
 
-       if (ctx == NULL || request->handle != 0)
+       if (ctx == NULL || a->handle != 0)
                return -EINVAL;
 
        /*
@@ -929,23 +930,23 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
         * set them both to 0, which will still let packets with
         * payload_length == 0 through.  In other words, if no packets
         * use the indirect payload, the iso buffer need not be mapped
-        * and the request->data pointer is ignored.
+        * and the a->data pointer is ignored.
         */
 
-       payload = (unsigned long)request->data - client->vm_start;
+       payload = (unsigned long)a->data - client->vm_start;
        buffer_end = client->buffer.page_count << PAGE_SHIFT;
-       if (request->data == 0 || client->buffer.pages == NULL ||
+       if (a->data == 0 || client->buffer.pages == NULL ||
            payload >= buffer_end) {
                payload = 0;
                buffer_end = 0;
        }
 
-       p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
+       p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets);
 
-       if (!access_ok(VERIFY_READ, p, request->size))
+       if (!access_ok(VERIFY_READ, p, a->size))
                return -EFAULT;
 
-       end = (void __user *)p + request->size;
+       end = (void __user *)p + a->size;
        count = 0;
        while (p < end) {
                if (get_user(control, &p->control))
@@ -995,61 +996,78 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
                count++;
        }
 
-       request->size    -= uptr_to_u64(p) - request->packets;
-       request->packets  = uptr_to_u64(p);
-       request->data     = client->vm_start + payload;
+       a->size    -= uptr_to_u64(p) - a->packets;
+       a->packets  = uptr_to_u64(p);
+       a->data     = client->vm_start + payload;
 
        return count;
 }
 
-static int ioctl_start_iso(struct client *client, void *buffer)
+static int ioctl_start_iso(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_start_iso *request = buffer;
+       struct fw_cdev_start_iso *a = &arg->start_iso;
 
-       if (client->iso_context == NULL || request->handle != 0)
+       if (client->iso_context == NULL || a->handle != 0)
                return -EINVAL;
 
-       if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
-               if (request->tags == 0 || request->tags > 15)
-                       return -EINVAL;
-
-               if (request->sync > 15)
-                       return -EINVAL;
-       }
+       if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE &&
+           (a->tags == 0 || a->tags > 15 || a->sync > 15))
+               return -EINVAL;
 
-       return fw_iso_context_start(client->iso_context, request->cycle,
-                                   request->sync, request->tags);
+       return fw_iso_context_start(client->iso_context,
+                                   a->cycle, a->sync, a->tags);
 }
 
-static int ioctl_stop_iso(struct client *client, void *buffer)
+static int ioctl_stop_iso(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_stop_iso *request = buffer;
+       struct fw_cdev_stop_iso *a = &arg->stop_iso;
 
-       if (client->iso_context == NULL || request->handle != 0)
+       if (client->iso_context == NULL || a->handle != 0)
                return -EINVAL;
 
        return fw_iso_context_stop(client->iso_context);
 }
 
-static int ioctl_get_cycle_timer(struct client *client, void *buffer)
+static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_get_cycle_timer *request = buffer;
+       struct fw_cdev_get_cycle_timer2 *a = &arg->get_cycle_timer2;
        struct fw_card *card = client->device->card;
-       unsigned long long bus_time;
-       struct timeval tv;
-       unsigned long flags;
+       struct timespec ts = {0, 0};
+       u32 cycle_time;
+       int ret = 0;
+
+       local_irq_disable();
+
+       cycle_time = card->driver->get_cycle_time(card);
 
-       preempt_disable();
-       local_irq_save(flags);
+       switch (a->clk_id) {
+       case CLOCK_REALTIME:      getnstimeofday(&ts);                   break;
+       case CLOCK_MONOTONIC:     do_posix_clock_monotonic_gettime(&ts); break;
+       case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts);                  break;
+       default:
+               ret = -EINVAL;
+       }
 
-       bus_time = card->driver->get_bus_time(card);
-       do_gettimeofday(&tv);
+       local_irq_enable();
 
-       local_irq_restore(flags);
-       preempt_enable();
+       a->tv_sec      = ts.tv_sec;
+       a->tv_nsec     = ts.tv_nsec;
+       a->cycle_timer = cycle_time;
+
+       return ret;
+}
+
+static int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg)
+{
+       struct fw_cdev_get_cycle_timer *a = &arg->get_cycle_timer;
+       struct fw_cdev_get_cycle_timer2 ct2;
+
+       ct2.clk_id = CLOCK_REALTIME;
+       ioctl_get_cycle_timer2(client, (union ioctl_arg *)&ct2);
+
+       a->local_time = ct2.tv_sec * USEC_PER_SEC + ct2.tv_nsec / NSEC_PER_USEC;
+       a->cycle_timer = ct2.cycle_timer;
 
-       request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
-       request->cycle_timer = bus_time & 0xffffffff;
        return 0;
 }
 
@@ -1220,33 +1238,32 @@ static int init_iso_resource(struct client *client,
        return ret;
 }
 
-static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
+static int ioctl_allocate_iso_resource(struct client *client,
+                                      union ioctl_arg *arg)
 {
-       struct fw_cdev_allocate_iso_resource *request = buffer;
-
-       return init_iso_resource(client, request, ISO_RES_ALLOC);
+       return init_iso_resource(client,
+                       &arg->allocate_iso_resource, ISO_RES_ALLOC);
 }
 
-static int ioctl_deallocate_iso_resource(struct client *client, void *buffer)
+static int ioctl_deallocate_iso_resource(struct client *client,
+                                        union ioctl_arg *arg)
 {
-       struct fw_cdev_deallocate *request = buffer;
-
-       return release_client_resource(client, request->handle,
-                                      release_iso_resource, NULL);
+       return release_client_resource(client,
+                       arg->deallocate.handle, release_iso_resource, NULL);
 }
 
-static int ioctl_allocate_iso_resource_once(struct client *client, void *buffer)
+static int ioctl_allocate_iso_resource_once(struct client *client,
+                                           union ioctl_arg *arg)
 {
-       struct fw_cdev_allocate_iso_resource *request = buffer;
-
-       return init_iso_resource(client, request, ISO_RES_ALLOC_ONCE);
+       return init_iso_resource(client,
+                       &arg->allocate_iso_resource, ISO_RES_ALLOC_ONCE);
 }
 
-static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffer)
+static int ioctl_deallocate_iso_resource_once(struct client *client,
+                                             union ioctl_arg *arg)
 {
-       struct fw_cdev_allocate_iso_resource *request = buffer;
-
-       return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE);
+       return init_iso_resource(client,
+                       &arg->allocate_iso_resource, ISO_RES_DEALLOC_ONCE);
 }
 
 /*
@@ -1254,16 +1271,17 @@ static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffe
  * 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)
+static int ioctl_get_speed(struct client *client, union ioctl_arg *arg)
 {
        return client->device->max_speed;
 }
 
-static int ioctl_send_broadcast_request(struct client *client, void *buffer)
+static int ioctl_send_broadcast_request(struct client *client,
+                                       union ioctl_arg *arg)
 {
-       struct fw_cdev_send_request *request = buffer;
+       struct fw_cdev_send_request *a = &arg->send_request;
 
-       switch (request->tcode) {
+       switch (a->tcode) {
        case TCODE_WRITE_QUADLET_REQUEST:
        case TCODE_WRITE_BLOCK_REQUEST:
                break;
@@ -1272,36 +1290,36 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer)
        }
 
        /* Security policy: Only allow accesses to Units Space. */
-       if (request->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END)
+       if (a->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END)
                return -EACCES;
 
-       return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100);
+       return init_request(client, a, LOCAL_BUS | 0x3f, SCODE_100);
 }
 
-static int ioctl_send_stream_packet(struct client *client, void *buffer)
+static int ioctl_send_stream_packet(struct client *client, union ioctl_arg *arg)
 {
-       struct fw_cdev_send_stream_packet *p = buffer;
+       struct fw_cdev_send_stream_packet *a = &arg->send_stream_packet;
        struct fw_cdev_send_request request;
        int dest;
 
-       if (p->speed > client->device->card->link_speed ||
-           p->length > 1024 << p->speed)
+       if (a->speed > client->device->card->link_speed ||
+           a->length > 1024 << a->speed)
                return -EIO;
 
-       if (p->tag > 3 || p->channel > 63 || p->sy > 15)
+       if (a->tag > 3 || a->channel > 63 || a->sy > 15)
                return -EINVAL;
 
-       dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy);
+       dest = fw_stream_packet_destination_id(a->tag, a->channel, a->sy);
        request.tcode           = TCODE_STREAM_DATA;
-       request.length          = p->length;
-       request.closure         = p->closure;
-       request.data            = p->data;
-       request.generation      = p->generation;
+       request.length          = a->length;
+       request.closure         = a->closure;
+       request.data            = a->data;
+       request.generation      = a->generation;
 
-       return init_request(client, &request, dest, p->speed);
+       return init_request(client, &request, dest, a->speed);
 }
 
-static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
+static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = {
        ioctl_get_info,
        ioctl_send_request,
        ioctl_allocate,
@@ -1322,47 +1340,35 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
        ioctl_get_speed,
        ioctl_send_broadcast_request,
        ioctl_send_stream_packet,
+       ioctl_get_cycle_timer2,
 };
 
 static int dispatch_ioctl(struct client *client,
                          unsigned int cmd, void __user *arg)
 {
-       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;
-       })];
+       union ioctl_arg buffer;
        int ret;
 
+       if (fw_device_is_shutdown(client->device))
+               return -ENODEV;
+
        if (_IOC_TYPE(cmd) != '#' ||
            _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers))
                return -EINVAL;
 
        if (_IOC_DIR(cmd) & _IOC_WRITE) {
                if (_IOC_SIZE(cmd) > sizeof(buffer) ||
-                   copy_from_user(buffer, arg, _IOC_SIZE(cmd)))
+                   copy_from_user(&buffer, arg, _IOC_SIZE(cmd)))
                        return -EFAULT;
        }
 
-       ret = ioctl_handlers[_IOC_NR(cmd)](client, buffer);
+       ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer);
        if (ret < 0)
                return ret;
 
        if (_IOC_DIR(cmd) & _IOC_READ) {
                if (_IOC_SIZE(cmd) > sizeof(buffer) ||
-                   copy_to_user(arg, buffer, _IOC_SIZE(cmd)))
+                   copy_to_user(arg, &buffer, _IOC_SIZE(cmd)))
                        return -EFAULT;
        }
 
@@ -1372,24 +1378,14 @@ static int dispatch_ioctl(struct client *client,
 static long fw_device_op_ioctl(struct file *file,
                               unsigned int cmd, unsigned long arg)
 {
-       struct client *client = file->private_data;
-
-       if (fw_device_is_shutdown(client->device))
-               return -ENODEV;
-
-       return dispatch_ioctl(client, cmd, (void __user *) arg);
+       return dispatch_ioctl(file->private_data, cmd, (void __user *)arg);
 }
 
 #ifdef CONFIG_COMPAT
 static long fw_device_op_compat_ioctl(struct file *file,
                                      unsigned int cmd, unsigned long arg)
 {
-       struct client *client = file->private_data;
-
-       if (fw_device_is_shutdown(client->device))
-               return -ENODEV;
-
-       return dispatch_ioctl(client, cmd, compat_ptr(arg));
+       return dispatch_ioctl(file->private_data, cmd, compat_ptr(arg));
 }
 #endif
 
index 9d0dfcbe2c1c82561bf1f026bac88f08324b3037..014cabd3afda56122bb433646a71f0180b3252e5 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/bug.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -43,7 +44,7 @@
 
 #include "core.h"
 
-void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p)
+void fw_csr_iterator_init(struct fw_csr_iterator *ci, const u32 *p)
 {
        ci->p = p + 1;
        ci->end = ci->p + (p[0] >> 16);
@@ -59,9 +60,76 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
 }
 EXPORT_SYMBOL(fw_csr_iterator_next);
 
+static const u32 *search_leaf(const u32 *directory, int search_key)
+{
+       struct fw_csr_iterator ci;
+       int last_key = 0, key, value;
+
+       fw_csr_iterator_init(&ci, directory);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               if (last_key == search_key &&
+                   key == (CSR_DESCRIPTOR | CSR_LEAF))
+                       return ci.p - 1 + value;
+
+               last_key = key;
+       }
+
+       return NULL;
+}
+
+static int textual_leaf_to_string(const u32 *block, char *buf, size_t size)
+{
+       unsigned int quadlets, i;
+       char c;
+
+       if (!size || !buf)
+               return -EINVAL;
+
+       quadlets = min(block[0] >> 16, 256U);
+       if (quadlets < 2)
+               return -ENODATA;
+
+       if (block[1] != 0 || block[2] != 0)
+               /* unknown language/character set */
+               return -ENODATA;
+
+       block += 3;
+       quadlets -= 2;
+       for (i = 0; i < quadlets * 4 && i < size - 1; i++) {
+               c = block[i / 4] >> (24 - 8 * (i % 4));
+               if (c == '\0')
+                       break;
+               buf[i] = c;
+       }
+       buf[i] = '\0';
+
+       return i;
+}
+
+/**
+ * fw_csr_string - reads a string from the configuration ROM
+ * @directory: e.g. root directory or unit directory
+ * @key: the key of the preceding directory entry
+ * @buf: where to put the string
+ * @size: size of @buf, in bytes
+ *
+ * The string is taken from a minimal ASCII text descriptor leaf after
+ * the immediate entry with @key.  The string is zero-terminated.
+ * Returns strlen(buf) or a negative error code.
+ */
+int fw_csr_string(const u32 *directory, int key, char *buf, size_t size)
+{
+       const u32 *leaf = search_leaf(directory, key);
+       if (!leaf)
+               return -ENOENT;
+
+       return textual_leaf_to_string(leaf, buf, size);
+}
+EXPORT_SYMBOL(fw_csr_string);
+
 static bool is_fw_unit(struct device *dev);
 
-static int match_unit_directory(u32 *directory, u32 match_flags,
+static int match_unit_directory(const u32 *directory, u32 match_flags,
                                const struct ieee1394_device_id *id)
 {
        struct fw_csr_iterator ci;
@@ -195,7 +263,7 @@ static ssize_t show_immediate(struct device *dev,
        struct config_rom_attribute *attr =
                container_of(dattr, struct config_rom_attribute, attr);
        struct fw_csr_iterator ci;
-       u32 *dir;
+       const u32 *dir;
        int key, value, ret = -ENOENT;
 
        down_read(&fw_device_rwsem);
@@ -226,10 +294,10 @@ static ssize_t show_text_leaf(struct device *dev,
 {
        struct config_rom_attribute *attr =
                container_of(dattr, struct config_rom_attribute, attr);
-       struct fw_csr_iterator ci;
-       u32 *dir, *block = NULL, *p, *end;
-       int length, key, value, last_key = 0, ret = -ENOENT;
-       char *b;
+       const u32 *dir;
+       size_t bufsize;
+       char dummy_buf[2];
+       int ret;
 
        down_read(&fw_device_rwsem);
 
@@ -238,40 +306,23 @@ static ssize_t show_text_leaf(struct device *dev,
        else
                dir = fw_device(dev)->config_rom + 5;
 
-       fw_csr_iterator_init(&ci, dir);
-       while (fw_csr_iterator_next(&ci, &key, &value)) {
-               if (attr->key == last_key &&
-                   key == (CSR_DESCRIPTOR | CSR_LEAF))
-                       block = ci.p - 1 + value;
-               last_key = key;
+       if (buf) {
+               bufsize = PAGE_SIZE - 1;
+       } else {
+               buf = dummy_buf;
+               bufsize = 1;
        }
 
-       if (block == NULL)
-               goto out;
-
-       length = min(block[0] >> 16, 256U);
-       if (length < 3)
-               goto out;
-
-       if (block[1] != 0 || block[2] != 0)
-               /* Unknown encoding. */
-               goto out;
+       ret = fw_csr_string(dir, attr->key, buf, bufsize);
 
-       if (buf == NULL) {
-               ret = length * 4;
-               goto out;
+       if (ret >= 0) {
+               /* Strip trailing whitespace and add newline. */
+               while (ret > 0 && isspace(buf[ret - 1]))
+                       ret--;
+               strcpy(buf + ret, "\n");
+               ret++;
        }
 
-       b = buf;
-       end = &block[length + 1];
-       for (p = &block[3]; p < end; p++, b += 4)
-               * (u32 *) b = (__force u32) __cpu_to_be32(*p);
-
-       /* Strip trailing whitespace and add newline. */
-       while (b--, (isspace(*b) || *b == '\0') && b > buf);
-       strcpy(b + 1, "\n");
-       ret = b + 2 - buf;
- out:
        up_read(&fw_device_rwsem);
 
        return ret;
@@ -371,7 +422,7 @@ static ssize_t guid_show(struct device *dev,
        return ret;
 }
 
-static int units_sprintf(char *buf, u32 *directory)
+static int units_sprintf(char *buf, const u32 *directory)
 {
        struct fw_csr_iterator ci;
        int key, value;
@@ -441,28 +492,29 @@ static int read_rom(struct fw_device *device,
        return rcode;
 }
 
-#define READ_BIB_ROM_SIZE      256
-#define READ_BIB_STACK_SIZE    16
+#define MAX_CONFIG_ROM_SIZE 256
 
 /*
  * Read the bus info block, perform a speed probe, and read all of the rest of
  * the config ROM.  We do all this with a cached bus generation.  If the bus
- * generation changes under us, read_bus_info_block will fail and get retried.
+ * generation changes under us, read_config_rom will fail and get retried.
  * It's better to start all over in this case because the node from which we
  * are reading the ROM may have changed the ROM during the reset.
  */
-static int read_bus_info_block(struct fw_device *device, int generation)
+static int read_config_rom(struct fw_device *device, int generation)
 {
-       u32 *rom, *stack, *old_rom, *new_rom;
+       const u32 *old_rom, *new_rom;
+       u32 *rom, *stack;
        u32 sp, key;
        int i, end, length, ret = -1;
 
-       rom = kmalloc(sizeof(*rom) * READ_BIB_ROM_SIZE +
-                     sizeof(*stack) * READ_BIB_STACK_SIZE, GFP_KERNEL);
+       rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
+                     sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
        if (rom == NULL)
                return -ENOMEM;
 
-       stack = &rom[READ_BIB_ROM_SIZE];
+       stack = &rom[MAX_CONFIG_ROM_SIZE];
+       memset(rom, 0, sizeof(*rom) * MAX_CONFIG_ROM_SIZE);
 
        device->max_speed = SCODE_100;
 
@@ -529,40 +581,54 @@ static int read_bus_info_block(struct fw_device *device, int generation)
                 */
                key = stack[--sp];
                i = key & 0xffffff;
-               if (i >= READ_BIB_ROM_SIZE)
-                       /*
-                        * The reference points outside the standard
-                        * config rom area, something's fishy.
-                        */
+               if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE))
                        goto out;
 
                /* Read header quadlet for the block to get the length. */
                if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
                        goto out;
                end = i + (rom[i] >> 16) + 1;
-               i++;
-               if (end > READ_BIB_ROM_SIZE)
+               if (end > MAX_CONFIG_ROM_SIZE) {
                        /*
-                        * This block extends outside standard config
-                        * area (and the array we're reading it
-                        * into).  That's broken, so ignore this
-                        * device.
+                        * This block extends outside the config ROM which is
+                        * a firmware bug.  Ignore this whole block, i.e.
+                        * simply set a fake block length of 0.
                         */
-                       goto out;
+                       fw_error("skipped invalid ROM block %x at %llx\n",
+                                rom[i],
+                                i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
+                       rom[i] = 0;
+                       end = i;
+               }
+               i++;
 
                /*
                 * Now read in the block.  If this is a directory
                 * block, check the entries as we read them to see if
                 * it references another block, and push it in that case.
                 */
-               while (i < end) {
+               for (; i < end; i++) {
                        if (read_rom(device, generation, i, &rom[i]) !=
                            RCODE_COMPLETE)
                                goto out;
-                       if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
-                           sp < READ_BIB_STACK_SIZE)
-                               stack[sp++] = i + rom[i];
-                       i++;
+
+                       if ((key >> 30) != 3 || (rom[i] >> 30) < 2)
+                               continue;
+                       /*
+                        * Offset points outside the ROM.  May be a firmware
+                        * bug or an Extended ROM entry (IEEE 1212-2001 clause
+                        * 7.7.18).  Simply overwrite this pointer here by a
+                        * fake immediate entry so that later iterators over
+                        * the ROM don't have to check offsets all the time.
+                        */
+                       if (i + (rom[i] & 0xffffff) >= MAX_CONFIG_ROM_SIZE) {
+                               fw_error("skipped unsupported ROM entry %x at %llx\n",
+                                        rom[i],
+                                        i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
+                               rom[i] = 0;
+                               continue;
+                       }
+                       stack[sp++] = i + rom[i];
                }
                if (length < i)
                        length = i;
@@ -905,7 +971,7 @@ static void fw_device_init(struct work_struct *work)
         * device.
         */
 
-       if (read_bus_info_block(device, device->generation) < 0) {
+       if (read_config_rom(device, device->generation) < 0) {
                if (device->config_rom_retries < MAX_RETRIES &&
                    atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
                        device->config_rom_retries++;
@@ -1022,7 +1088,7 @@ enum {
 };
 
 /* Reread and compare bus info block and header of root directory */
-static int reread_bus_info_block(struct fw_device *device, int generation)
+static int reread_config_rom(struct fw_device *device, int generation)
 {
        u32 q;
        int i;
@@ -1048,7 +1114,7 @@ static void fw_device_refresh(struct work_struct *work)
        struct fw_card *card = device->card;
        int node_id = device->node_id;
 
-       switch (reread_bus_info_block(device, device->generation)) {
+       switch (reread_config_rom(device, device->generation)) {
        case REREAD_BIB_ERROR:
                if (device->config_rom_retries < MAX_RETRIES / 2 &&
                    atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
@@ -1082,7 +1148,7 @@ static void fw_device_refresh(struct work_struct *work)
         */
        device_for_each_child(&device->device, NULL, shutdown_unit);
 
-       if (read_bus_info_block(device, device->generation) < 0) {
+       if (read_config_rom(device, device->generation) < 0) {
                if (device->config_rom_retries < MAX_RETRIES &&
                    atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
                        device->config_rom_retries++;
index 495849eb13cc2a3858f3675dc81b1359af706a72..673b03f8b4ecd6cbe1ac577e845350a6bcb7dca8 100644 (file)
@@ -921,23 +921,15 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
                void *payload, size_t length, void *callback_data)
 {
        int reg = offset & ~CSR_REGISTER_BASE;
-       unsigned long long bus_time;
        __be32 *data = payload;
        int rcode = RCODE_COMPLETE;
 
        switch (reg) {
        case CSR_CYCLE_TIME:
-       case CSR_BUS_TIME:
-               if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) {
-                       rcode = RCODE_TYPE_ERROR;
-                       break;
-               }
-
-               bus_time = card->driver->get_bus_time(card);
-               if (reg == CSR_CYCLE_TIME)
-                       *data = cpu_to_be32(bus_time);
+               if (TCODE_IS_READ_REQUEST(tcode) && length == 4)
+                       *data = cpu_to_be32(card->driver->get_cycle_time(card));
                else
-                       *data = cpu_to_be32(bus_time >> 25);
+                       rcode = RCODE_TYPE_ERROR;
                break;
 
        case CSR_BROADCAST_CHANNEL:
@@ -968,6 +960,9 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
        case CSR_BUSY_TIMEOUT:
                /* FIXME: Implement this. */
 
+       case CSR_BUS_TIME:
+               /* Useless without initialization by the bus manager. */
+
        default:
                rcode = RCODE_ADDRESS_ERROR;
                break;
index ed3b1a765c006887f9e338bb6c6457cb9c0f2f49..fb0321300cce4a01b646e77a5f0d040c0f46f25d 100644 (file)
@@ -70,7 +70,7 @@ struct fw_card_driver {
        int (*enable_phys_dma)(struct fw_card *card,
                               int node_id, int generation);
 
-       u64 (*get_bus_time)(struct fw_card *card);
+       u32 (*get_cycle_time)(struct fw_card *card);
 
        struct fw_iso_context *
        (*allocate_iso_context)(struct fw_card *card,
index 43ebf337b131152bb0503372cadd8173535e5e62..75dc6988cffd5d174ae8eb5445b5ce8744e0f4b0 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 
-#include <asm/atomic.h>
 #include <asm/byteorder.h>
 #include <asm/page.h>
 #include <asm/system.h>
@@ -73,20 +72,6 @@ struct descriptor {
        __le16 transfer_status;
 } __attribute__((aligned(16)));
 
-struct db_descriptor {
-       __le16 first_size;
-       __le16 control;
-       __le16 second_req_count;
-       __le16 first_req_count;
-       __le32 branch_address;
-       __le16 second_res_count;
-       __le16 first_res_count;
-       __le32 reserved0;
-       __le32 first_buffer;
-       __le32 second_buffer;
-       __le32 reserved1;
-} __attribute__((aligned(16)));
-
 #define CONTROL_SET(regs)      (regs)
 #define CONTROL_CLEAR(regs)    ((regs) + 4)
 #define COMMAND_PTR(regs)      ((regs) + 12)
@@ -181,31 +166,16 @@ struct fw_ohci {
        struct fw_card card;
 
        __iomem char *registers;
-       dma_addr_t self_id_bus;
-       __le32 *self_id_cpu;
-       struct tasklet_struct bus_reset_tasklet;
        int node_id;
        int generation;
        int request_generation; /* for timestamping incoming requests */
-       atomic_t bus_seconds;
-
-       bool use_dualbuffer;
-       bool old_uninorth;
-       bool bus_reset_packet_quirk;
+       unsigned quirks;
 
        /*
         * Spinlock for accessing fw_ohci data.  Never call out of
         * this driver with this lock held.
         */
        spinlock_t lock;
-       u32 self_id_buffer[512];
-
-       /* Config rom buffers */
-       __be32 *config_rom;
-       dma_addr_t config_rom_bus;
-       __be32 *next_config_rom;
-       dma_addr_t next_config_rom_bus;
-       __be32 next_header;
 
        struct ar_context ar_request_ctx;
        struct ar_context ar_response_ctx;
@@ -217,6 +187,18 @@ struct fw_ohci {
        u64 ir_context_channels;
        u32 ir_context_mask;
        struct iso_context *ir_context_list;
+
+       __be32    *config_rom;
+       dma_addr_t config_rom_bus;
+       __be32    *next_config_rom;
+       dma_addr_t next_config_rom_bus;
+       __be32     next_header;
+
+       __le32    *self_id_cpu;
+       dma_addr_t self_id_bus;
+       struct tasklet_struct bus_reset_tasklet;
+
+       u32 self_id_buffer[512];
 };
 
 static inline struct fw_ohci *fw_ohci(struct fw_card *card)
@@ -249,6 +231,30 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
 
 static char ohci_driver_name[] = KBUILD_MODNAME;
 
+#define QUIRK_CYCLE_TIMER              1
+#define QUIRK_RESET_PACKET             2
+#define QUIRK_BE_HEADERS               4
+
+/* In case of multiple matches in ohci_quirks[], only the first one is used. */
+static const struct {
+       unsigned short vendor, device, flags;
+} ohci_quirks[] = {
+       {PCI_VENDOR_ID_TI,      PCI_ANY_ID,     QUIRK_RESET_PACKET},
+       {PCI_VENDOR_ID_AL,      PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
+       {PCI_VENDOR_ID_NEC,     PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
+       {PCI_VENDOR_ID_VIA,     PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
+       {PCI_VENDOR_ID_APPLE,   PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
+};
+
+/* This overrides anything that was found in ohci_quirks[]. */
+static int param_quirks;
+module_param_named(quirks, param_quirks, int, 0644);
+MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
+       ", nonatomic cycle timer = "    __stringify(QUIRK_CYCLE_TIMER)
+       ", reset packet generation = "  __stringify(QUIRK_RESET_PACKET)
+       ", AR/selfID endianess = "      __stringify(QUIRK_BE_HEADERS)
+       ")");
+
 #ifdef CONFIG_FIREWIRE_OHCI_DEBUG
 
 #define OHCI_PARAM_DEBUG_AT_AR         1
@@ -275,7 +281,7 @@ static void log_irqs(u32 evt)
            !(evt & OHCI1394_busReset))
                return;
 
-       fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+       fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
            evt & OHCI1394_selfIDComplete       ? " selfID"             : "",
            evt & OHCI1394_RQPkt                ? " AR_req"             : "",
            evt & OHCI1394_RSPkt                ? " AR_resp"            : "",
@@ -285,7 +291,6 @@ static void log_irqs(u32 evt)
            evt & OHCI1394_isochTx              ? " IT"                 : "",
            evt & OHCI1394_postedWriteErr       ? " postedWriteErr"     : "",
            evt & OHCI1394_cycleTooLong         ? " cycleTooLong"       : "",
-           evt & OHCI1394_cycle64Seconds       ? " cycle64Seconds"     : "",
            evt & OHCI1394_cycleInconsistent    ? " cycleInconsistent"  : "",
            evt & OHCI1394_regAccessFail        ? " regAccessFail"      : "",
            evt & OHCI1394_busReset             ? " busReset"           : "",
@@ -293,8 +298,7 @@ static void log_irqs(u32 evt)
                    OHCI1394_RSPkt | OHCI1394_reqTxComplete |
                    OHCI1394_respTxComplete | OHCI1394_isochRx |
                    OHCI1394_isochTx | OHCI1394_postedWriteErr |
-                   OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
-                   OHCI1394_cycleInconsistent |
+                   OHCI1394_cycleTooLong | OHCI1394_cycleInconsistent |
                    OHCI1394_regAccessFail | OHCI1394_busReset)
                                                ? " ?"                  : "");
 }
@@ -524,7 +528,7 @@ static void ar_context_release(struct ar_context *ctx)
 
 #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
 #define cond_le32_to_cpu(v) \
-       (ohci->old_uninorth ? (__force __u32)(v) : le32_to_cpu(v))
+       (ohci->quirks & QUIRK_BE_HEADERS ? (__force __u32)(v) : le32_to_cpu(v))
 #else
 #define cond_le32_to_cpu(v) le32_to_cpu(v)
 #endif
@@ -605,7 +609,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
         * at a slightly incorrect time (in bus_reset_tasklet).
         */
        if (evt == OHCI1394_evt_bus_reset) {
-               if (!ohci->bus_reset_packet_quirk)
+               if (!(ohci->quirks & QUIRK_RESET_PACKET))
                        ohci->request_generation = (p.header[2] >> 16) & 0xff;
        } else if (ctx == &ohci->ar_request_ctx) {
                fw_core_handle_request(&ohci->card, &p);
@@ -1329,7 +1333,7 @@ static void bus_reset_tasklet(unsigned long data)
        context_stop(&ohci->at_response_ctx);
        reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
 
-       if (ohci->bus_reset_packet_quirk)
+       if (ohci->quirks & QUIRK_RESET_PACKET)
                ohci->request_generation = generation;
 
        /*
@@ -1384,7 +1388,7 @@ static void bus_reset_tasklet(unsigned long data)
 static irqreturn_t irq_handler(int irq, void *data)
 {
        struct fw_ohci *ohci = data;
-       u32 event, iso_event, cycle_time;
+       u32 event, iso_event;
        int i;
 
        event = reg_read(ohci, OHCI1394_IntEventClear);
@@ -1454,12 +1458,6 @@ static irqreturn_t irq_handler(int irq, void *data)
                        fw_notify("isochronous cycle inconsistent\n");
        }
 
-       if (event & OHCI1394_cycle64Seconds) {
-               cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-               if ((cycle_time & 0x80000000) == 0)
-                       atomic_inc(&ohci->bus_seconds);
-       }
-
        return IRQ_HANDLED;
 }
 
@@ -1553,8 +1551,7 @@ static int ohci_enable(struct fw_card *card,
                  OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
                  OHCI1394_isochRx | OHCI1394_isochTx |
                  OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
-                 OHCI1394_cycleInconsistent |
-                 OHCI1394_cycle64Seconds | OHCI1394_regAccessFail |
+                 OHCI1394_cycleInconsistent | OHCI1394_regAccessFail |
                  OHCI1394_masterIntEnable);
        if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
                reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
@@ -1794,16 +1791,61 @@ static int ohci_enable_phys_dma(struct fw_card *card,
 #endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
 }
 
-static u64 ohci_get_bus_time(struct fw_card *card)
+static u32 cycle_timer_ticks(u32 cycle_timer)
 {
-       struct fw_ohci *ohci = fw_ohci(card);
-       u32 cycle_time;
-       u64 bus_time;
+       u32 ticks;
 
-       cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-       bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time;
+       ticks = cycle_timer & 0xfff;
+       ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
+       ticks += (3072 * 8000) * (cycle_timer >> 25);
+
+       return ticks;
+}
+
+/*
+ * Some controllers exhibit one or more of the following bugs when updating the
+ * iso cycle timer register:
+ *  - When the lowest six bits are wrapping around to zero, a read that happens
+ *    at the same time will return garbage in the lowest ten bits.
+ *  - When the cycleOffset field wraps around to zero, the cycleCount field is
+ *    not incremented for about 60 ns.
+ *  - Occasionally, the entire register reads zero.
+ *
+ * To catch these, we read the register three times and ensure that the
+ * difference between each two consecutive reads is approximately the same, i.e.
+ * less than twice the other.  Furthermore, any negative difference indicates an
+ * error.  (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
+ * execute, so we have enough precision to compute the ratio of the differences.)
+ */
+static u32 ohci_get_cycle_time(struct fw_card *card)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       u32 c0, c1, c2;
+       u32 t0, t1, t2;
+       s32 diff01, diff12;
+       int i;
 
-       return bus_time;
+       c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+
+       if (ohci->quirks & QUIRK_CYCLE_TIMER) {
+               i = 0;
+               c1 = c2;
+               c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+               do {
+                       c0 = c1;
+                       c1 = c2;
+                       c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+                       t0 = cycle_timer_ticks(c0);
+                       t1 = cycle_timer_ticks(c1);
+                       t2 = cycle_timer_ticks(c2);
+                       diff01 = t1 - t0;
+                       diff12 = t2 - t1;
+               } while ((diff01 <= 0 || diff12 <= 0 ||
+                         diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
+                        && i++ < 20);
+       }
+
+       return c2;
 }
 
 static void copy_iso_headers(struct iso_context *ctx, void *p)
@@ -1828,52 +1870,6 @@ static void copy_iso_headers(struct iso_context *ctx, void *p)
        ctx->header_length += ctx->base.header_size;
 }
 
-static int handle_ir_dualbuffer_packet(struct context *context,
-                                      struct descriptor *d,
-                                      struct descriptor *last)
-{
-       struct iso_context *ctx =
-               container_of(context, struct iso_context, context);
-       struct db_descriptor *db = (struct db_descriptor *) d;
-       __le32 *ir_header;
-       size_t header_length;
-       void *p, *end;
-
-       if (db->first_res_count != 0 && db->second_res_count != 0) {
-               if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) {
-                       /* This descriptor isn't done yet, stop iteration. */
-                       return 0;
-               }
-               ctx->excess_bytes -= le16_to_cpu(db->second_req_count);
-       }
-
-       header_length = le16_to_cpu(db->first_req_count) -
-               le16_to_cpu(db->first_res_count);
-
-       p = db + 1;
-       end = p + header_length;
-       while (p < end) {
-               copy_iso_headers(ctx, p);
-               ctx->excess_bytes +=
-                       (le32_to_cpu(*(__le32 *)(p + 4)) >> 16) & 0xffff;
-               p += max(ctx->base.header_size, (size_t)8);
-       }
-
-       ctx->excess_bytes -= le16_to_cpu(db->second_req_count) -
-               le16_to_cpu(db->second_res_count);
-
-       if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) {
-               ir_header = (__le32 *) (db + 1);
-               ctx->base.callback(&ctx->base,
-                                  le32_to_cpu(ir_header[0]) & 0xffff,
-                                  ctx->header_length, ctx->header,
-                                  ctx->base.callback_data);
-               ctx->header_length = 0;
-       }
-
-       return 1;
-}
-
 static int handle_ir_packet_per_buffer(struct context *context,
                                       struct descriptor *d,
                                       struct descriptor *last)
@@ -1960,10 +1956,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
                channels = &ohci->ir_context_channels;
                mask = &ohci->ir_context_mask;
                list = ohci->ir_context_list;
-               if (ohci->use_dualbuffer)
-                       callback = handle_ir_dualbuffer_packet;
-               else
-                       callback = handle_ir_packet_per_buffer;
+               callback = handle_ir_packet_per_buffer;
        }
 
        spin_lock_irqsave(&ohci->lock, flags);
@@ -2026,8 +2019,6 @@ static int ohci_start_iso(struct fw_iso_context *base,
        } else {
                index = ctx - ohci->ir_context_list;
                control = IR_CONTEXT_ISOCH_HEADER;
-               if (ohci->use_dualbuffer)
-                       control |= IR_CONTEXT_DUAL_BUFFER_MODE;
                match = (tags << 28) | (sync << 8) | ctx->base.channel;
                if (cycle >= 0) {
                        match |= (cycle & 0x07fff) << 12;
@@ -2188,92 +2179,6 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base,
        return 0;
 }
 
-static int ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
-                                            struct fw_iso_packet *packet,
-                                            struct fw_iso_buffer *buffer,
-                                            unsigned long payload)
-{
-       struct iso_context *ctx = container_of(base, struct iso_context, base);
-       struct db_descriptor *db = NULL;
-       struct descriptor *d;
-       struct fw_iso_packet *p;
-       dma_addr_t d_bus, page_bus;
-       u32 z, header_z, length, rest;
-       int page, offset, packet_count, header_size;
-
-       /*
-        * FIXME: Cycle lost behavior should be configurable: lose
-        * packet, retransmit or terminate..
-        */
-
-       p = packet;
-       z = 2;
-
-       /*
-        * The OHCI controller puts the isochronous header and trailer in the
-        * buffer, so we need at least 8 bytes.
-        */
-       packet_count = p->header_length / ctx->base.header_size;
-       header_size = packet_count * max(ctx->base.header_size, (size_t)8);
-
-       /* Get header size in number of descriptors. */
-       header_z = DIV_ROUND_UP(header_size, sizeof(*d));
-       page     = payload >> PAGE_SHIFT;
-       offset   = payload & ~PAGE_MASK;
-       rest     = p->payload_length;
-       /*
-        * The controllers I've tested have not worked correctly when
-        * second_req_count is zero.  Rather than do something we know won't
-        * work, return an error
-        */
-       if (rest == 0)
-               return -EINVAL;
-
-       while (rest > 0) {
-               d = context_get_descriptors(&ctx->context,
-                                           z + header_z, &d_bus);
-               if (d == NULL)
-                       return -ENOMEM;
-
-               db = (struct db_descriptor *) d;
-               db->control = cpu_to_le16(DESCRIPTOR_STATUS |
-                                         DESCRIPTOR_BRANCH_ALWAYS);
-               db->first_size =
-                   cpu_to_le16(max(ctx->base.header_size, (size_t)8));
-               if (p->skip && rest == p->payload_length) {
-                       db->control |= cpu_to_le16(DESCRIPTOR_WAIT);
-                       db->first_req_count = db->first_size;
-               } else {
-                       db->first_req_count = cpu_to_le16(header_size);
-               }
-               db->first_res_count = db->first_req_count;
-               db->first_buffer = cpu_to_le32(d_bus + sizeof(*db));
-
-               if (p->skip && rest == p->payload_length)
-                       length = 4;
-               else if (offset + rest < PAGE_SIZE)
-                       length = rest;
-               else
-                       length = PAGE_SIZE - offset;
-
-               db->second_req_count = cpu_to_le16(length);
-               db->second_res_count = db->second_req_count;
-               page_bus = page_private(buffer->pages[page]);
-               db->second_buffer = cpu_to_le32(page_bus + offset);
-
-               if (p->interrupt && length == rest)
-                       db->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS);
-
-               context_append(&ctx->context, d, z, header_z);
-               offset = (offset + length) & ~PAGE_MASK;
-               rest -= length;
-               if (offset == 0)
-                       page++;
-       }
-
-       return 0;
-}
-
 static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
                                        struct fw_iso_packet *packet,
                                        struct fw_iso_buffer *buffer,
@@ -2364,9 +2269,6 @@ static int ohci_queue_iso(struct fw_iso_context *base,
        spin_lock_irqsave(&ctx->context.ohci->lock, flags);
        if (base->type == FW_ISO_CONTEXT_TRANSMIT)
                ret = ohci_queue_iso_transmit(base, packet, buffer, payload);
-       else if (ctx->context.ohci->use_dualbuffer)
-               ret = ohci_queue_iso_receive_dualbuffer(base, packet,
-                                                       buffer, payload);
        else
                ret = ohci_queue_iso_receive_packet_per_buffer(base, packet,
                                                        buffer, payload);
@@ -2383,7 +2285,7 @@ static const struct fw_card_driver ohci_driver = {
        .send_response          = ohci_send_response,
        .cancel_packet          = ohci_cancel_packet,
        .enable_phys_dma        = ohci_enable_phys_dma,
-       .get_bus_time           = ohci_get_bus_time,
+       .get_cycle_time         = ohci_get_cycle_time,
 
        .allocate_iso_context   = ohci_allocate_iso_context,
        .free_iso_context       = ohci_free_iso_context,
@@ -2421,17 +2323,13 @@ static void ohci_pmac_off(struct pci_dev *dev)
 #define ohci_pmac_off(dev)
 #endif /* CONFIG_PPC_PMAC */
 
-#define PCI_VENDOR_ID_AGERE            PCI_VENDOR_ID_ATT
-#define PCI_DEVICE_ID_AGERE_FW643      0x5901
-#define PCI_DEVICE_ID_TI_TSB43AB23     0x8024
-
 static int __devinit pci_probe(struct pci_dev *dev,
                               const struct pci_device_id *ent)
 {
        struct fw_ohci *ohci;
        u32 bus_options, max_receive, link_speed, version;
        u64 guid;
-       int err;
+       int i, err, n_ir, n_it;
        size_t size;
 
        ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
@@ -2472,36 +2370,15 @@ static int __devinit pci_probe(struct pci_dev *dev,
                goto fail_iomem;
        }
 
-       version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
-#if 0
-       /* FIXME: make it a context option or remove dual-buffer mode */
-       ohci->use_dualbuffer = version >= OHCI_VERSION_1_1;
-#endif
-
-       /* dual-buffer mode is broken if more than one IR context is active */
-       if (dev->vendor == PCI_VENDOR_ID_AGERE &&
-           dev->device == PCI_DEVICE_ID_AGERE_FW643)
-               ohci->use_dualbuffer = false;
-
-       /* dual-buffer mode is broken */
-       if (dev->vendor == PCI_VENDOR_ID_RICOH &&
-           dev->device == PCI_DEVICE_ID_RICOH_R5C832)
-               ohci->use_dualbuffer = false;
-
-/* x86-32 currently doesn't use highmem for dma_alloc_coherent */
-#if !defined(CONFIG_X86_32)
-       /* dual-buffer mode is broken with descriptor addresses above 2G */
-       if (dev->vendor == PCI_VENDOR_ID_TI &&
-           (dev->device == PCI_DEVICE_ID_TI_TSB43AB22 ||
-            dev->device == PCI_DEVICE_ID_TI_TSB43AB23))
-               ohci->use_dualbuffer = false;
-#endif
-
-#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
-       ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
-                            dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
-#endif
-       ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
+       for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++)
+               if (ohci_quirks[i].vendor == dev->vendor &&
+                   (ohci_quirks[i].device == dev->device ||
+                    ohci_quirks[i].device == (unsigned short)PCI_ANY_ID)) {
+                       ohci->quirks = ohci_quirks[i].flags;
+                       break;
+               }
+       if (param_quirks)
+               ohci->quirks = param_quirks;
 
        ar_context_init(&ohci->ar_request_ctx, ohci,
                        OHCI1394_AsReqRcvContextControlSet);
@@ -2516,17 +2393,19 @@ static int __devinit pci_probe(struct pci_dev *dev,
                     OHCI1394_AsRspTrContextControlSet, handle_at_packet);
 
        reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
-       ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+       ohci->ir_context_channels = ~0ULL;
+       ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
        reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
-       size = sizeof(struct iso_context) * hweight32(ohci->it_context_mask);
-       ohci->it_context_list = kzalloc(size, GFP_KERNEL);
+       n_ir = hweight32(ohci->ir_context_mask);
+       size = sizeof(struct iso_context) * n_ir;
+       ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
 
        reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
-       ohci->ir_context_channels = ~0ULL;
-       ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
+       ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
        reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
-       size = sizeof(struct iso_context) * hweight32(ohci->ir_context_mask);
-       ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
+       n_it = hweight32(ohci->it_context_mask);
+       size = sizeof(struct iso_context) * n_it;
+       ohci->it_context_list = kzalloc(size, GFP_KERNEL);
 
        if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) {
                err = -ENOMEM;
@@ -2553,8 +2432,11 @@ static int __devinit pci_probe(struct pci_dev *dev,
        if (err)
                goto fail_self_id;
 
-       fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
-                 dev_name(&dev->dev), version >> 16, version & 0xff);
+       version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
+       fw_notify("Added fw-ohci device %s, OHCI v%x.%x, "
+                 "%d IR + %d IT contexts, quirks 0x%x\n",
+                 dev_name(&dev->dev), version >> 16, version & 0xff,
+                 n_ir, n_it, ohci->quirks);
 
        return 0;
 
@@ -2662,7 +2544,7 @@ static int pci_resume(struct pci_dev *dev)
 }
 #endif
 
-static struct pci_device_id pci_table[] = {
+static const struct pci_device_id pci_table[] = {
        { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_FIREWIRE_OHCI, ~0) },
        { }
 };
index 70fef40cd22f0f0d0d9c46add51943a51e6cea52..ca264f2fdf0caec95ebbb8c8289feb7ff0b38c9c 100644 (file)
@@ -1014,7 +1014,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
        return 0;
 }
 
-static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory)
+static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt,
+                                     const u32 *directory)
 {
        struct fw_csr_iterator ci;
        int key, value;
@@ -1027,7 +1028,7 @@ static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory)
        return 0;
 }
 
-static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
+static int sbp2_scan_unit_dir(struct sbp2_target *tgt, const u32 *directory,
                              u32 *model, u32 *firmware_revision)
 {
        struct fw_csr_iterator ci;
index 7a3de16fba0698e73bbd79df740efe4fe4e09630..75afe4f81e333b4bdeb8f036d4ec317da09e0e00 100644 (file)
@@ -239,47 +239,18 @@ static const struct fw_address_region fcp_region = {
 };
 
 /* Adjust the template string if models with longer names appear. */
-#define MAX_MODEL_NAME_LEN ((int)DIV_ROUND_UP(sizeof("FireDTV ????"), 4))
-
-static size_t model_name(u32 *directory, __be32 *buffer)
-{
-       struct fw_csr_iterator ci;
-       int i, length, key, value, last_key = 0;
-       u32 *block = NULL;
-
-       fw_csr_iterator_init(&ci, directory);
-       while (fw_csr_iterator_next(&ci, &key, &value)) {
-               if (last_key == CSR_MODEL &&
-                   key == (CSR_DESCRIPTOR | CSR_LEAF))
-                       block = ci.p - 1 + value;
-               last_key = key;
-       }
-
-       if (block == NULL)
-               return 0;
-
-       length = min((int)(block[0] >> 16) - 2, MAX_MODEL_NAME_LEN);
-       if (length <= 0)
-               return 0;
-
-       /* fast-forward to text string */
-       block += 3;
-
-       for (i = 0; i < length; i++)
-               buffer[i] = cpu_to_be32(block[i]);
-
-       return length * 4;
-}
+#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
 
 static int node_probe(struct device *dev)
 {
        struct firedtv *fdtv;
-       __be32 name[MAX_MODEL_NAME_LEN];
+       char name[MAX_MODEL_NAME_LEN];
        int name_len, err;
 
-       name_len = model_name(fw_unit(dev)->directory, name);
+       name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
+                                name, sizeof(name));
 
-       fdtv = fdtv_alloc(dev, &backend, (char *)name, name_len);
+       fdtv = fdtv_alloc(dev, &backend, name, name_len >= 0 ? name_len : 0);
        if (!fdtv)
                return -ENOMEM;
 
index 520ecf86cbb37b00bc7ec893bac4843b452fdeed..40b11013408ee163f4d295b91a51151a469f3ffa 100644 (file)
@@ -248,13 +248,20 @@ union fw_cdev_event {
 #define FW_CDEV_IOC_SEND_BROADCAST_REQUEST       _IOW('#', 0x12, struct fw_cdev_send_request)
 #define FW_CDEV_IOC_SEND_STREAM_PACKET           _IOW('#', 0x13, struct fw_cdev_send_stream_packet)
 
+/* available since kernel version 2.6.34 */
+#define FW_CDEV_IOC_GET_CYCLE_TIMER2   _IOWR('#', 0x14, struct fw_cdev_get_cycle_timer2)
+
 /*
  * FW_CDEV_VERSION History
  *  1  (2.6.22)  - initial version
  *  2  (2.6.30)  - changed &fw_cdev_event_iso_interrupt.header if
  *                 &fw_cdev_create_iso_context.header_size is 8 or more
+ *     (2.6.32)  - added time stamp to xmit &fw_cdev_event_iso_interrupt
+ *     (2.6.33)  - IR has always packet-per-buffer semantics now, not one of
+ *                 dual-buffer or packet-per-buffer depending on hardware
+ *  3  (2.6.34)  - made &fw_cdev_get_cycle_timer reliable
  */
-#define FW_CDEV_VERSION 2
+#define FW_CDEV_VERSION 3
 
 /**
  * struct fw_cdev_get_info - General purpose information ioctl
@@ -544,20 +551,43 @@ struct fw_cdev_stop_iso {
 /**
  * struct fw_cdev_get_cycle_timer - read cycle timer register
  * @local_time:   system time, in microseconds since the Epoch
- * @cycle_timer:  isochronous cycle timer, as per OHCI 1.1 clause 5.13
+ * @cycle_timer:  Cycle Time register contents
  *
  * The %FW_CDEV_IOC_GET_CYCLE_TIMER ioctl reads the isochronous cycle timer
- * and also the system clock.  This allows to express the receive time of an
- * isochronous packet as a system time with microsecond accuracy.
+ * and also the system clock (%CLOCK_REALTIME).  This allows to express the
+ * receive time of an isochronous packet as a system time.
  *
  * @cycle_timer consists of 7 bits cycleSeconds, 13 bits cycleCount, and
- * 12 bits cycleOffset, in host byte order.
+ * 12 bits cycleOffset, in host byte order.  Cf. the Cycle Time register
+ * per IEEE 1394 or Isochronous Cycle Timer register per OHCI-1394.
+ *
+ * In version 1 and 2 of the ABI, this ioctl returned unreliable (non-
+ * monotonic) @cycle_timer values on certain controllers.
  */
 struct fw_cdev_get_cycle_timer {
        __u64 local_time;
        __u32 cycle_timer;
 };
 
+/**
+ * struct fw_cdev_get_cycle_timer2 - read cycle timer register
+ * @tv_sec:       system time, seconds
+ * @tv_nsec:      system time, sub-seconds part in nanoseconds
+ * @clk_id:       input parameter, clock from which to get the system time
+ * @cycle_timer:  Cycle Time register contents
+ *
+ * The %FW_CDEV_IOC_GET_CYCLE_TIMER2 works like
+ * %FW_CDEV_IOC_GET_CYCLE_TIMER but lets you choose a clock like with POSIX'
+ * clock_gettime function.  Supported @clk_id values are POSIX' %CLOCK_REALTIME
+ * and %CLOCK_MONOTONIC and Linux' %CLOCK_MONOTONIC_RAW.
+ */
+struct fw_cdev_get_cycle_timer2 {
+       __s64 tv_sec;
+       __s32 tv_nsec;
+       __s32 clk_id;
+       __u32 cycle_timer;
+};
+
 /**
  * struct fw_cdev_allocate_iso_resource - (De)allocate a channel or bandwidth
  * @closure:   Passed back to userspace in correponding iso resource events
index a0e67150a729cadbc6782ab70821b2d5981a09ab..4bd94bf5e739253d17e5fb6ff3416e17966e8d09 100644 (file)
 #define CSR_DIRECTORY_ID       0x20
 
 struct fw_csr_iterator {
-       u32 *p;
-       u32 *end;
+       const u32 *p;
+       const u32 *end;
 };
 
-void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p);
+void fw_csr_iterator_init(struct fw_csr_iterator *ci, const u32 *p);
 int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value);
+int fw_csr_string(const u32 *directory, int key, char *buf, size_t size);
 
 extern struct bus_type fw_bus_type;
 
@@ -162,7 +163,7 @@ struct fw_device {
        struct mutex client_list_mutex;
        struct list_head client_list;
 
-       u32 *config_rom;
+       const u32 *config_rom;
        size_t config_rom_length;
        int config_rom_retries;
        unsigned is_local:1;
@@ -204,7 +205,7 @@ int fw_device_enable_phys_dma(struct fw_device *device);
  */
 struct fw_unit {
        struct device device;
-       u32 *directory;
+       const u32 *directory;
        struct fw_attribute_group attribute_group;
 };
 
index 0be82432058027a776709c590f51e24991aca869..c0e207c0c45aff409933f5063dfe598b82391d2d 100644 (file)
 #define PCI_VENDOR_ID_TI               0x104c
 #define PCI_DEVICE_ID_TI_TVP4020       0x3d07
 #define PCI_DEVICE_ID_TI_4450          0x8011
-#define PCI_DEVICE_ID_TI_TSB43AB22     0x8023
 #define PCI_DEVICE_ID_TI_XX21_XX11     0x8031
 #define PCI_DEVICE_ID_TI_XX21_XX11_FM  0x8033
 #define PCI_DEVICE_ID_TI_XX21_XX11_SD  0x8034