]> err.no Git - linux-2.6/commitdiff
firewire: Implement functionality to stop isochronous DMA contexts.
authorKristian Høgsberg <krh@redhat.com>
Fri, 16 Feb 2007 22:34:42 +0000 (17:34 -0500)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Fri, 9 Mar 2007 21:02:59 +0000 (22:02 +0100)
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
drivers/firewire/fw-device-cdev.c
drivers/firewire/fw-device-cdev.h
drivers/firewire/fw-iso.c
drivers/firewire/fw-ohci.c
drivers/firewire/fw-transaction.h

index b738c997ef39ce5b63aeb49c55c8944e53f5ec74..1ce33d4f91a32bf0dac7d0c1f9effc412d84e62b 100644 (file)
@@ -514,6 +514,11 @@ static int ioctl_start_iso(struct client *client, void __user *arg)
                                    request.speed, request.cycle);
 }
 
+static int ioctl_stop_iso(struct client *client, void __user *arg)
+{
+       return fw_iso_context_stop(client->iso_context);
+}
+
 static int
 dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
 {
@@ -532,6 +537,8 @@ dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
                return ioctl_queue_iso(client, arg);
        case FW_CDEV_IOC_START_ISO:
                return ioctl_start_iso(client, arg);
+       case FW_CDEV_IOC_STOP_ISO:
+               return ioctl_stop_iso(client, arg);
        default:
                return -EINVAL;
        }
index ac91ce501bfe4a5387ec5f4cbee727a6331e559a..257dc872f46d411355c96ffed56f17a861f6006d 100644 (file)
@@ -98,6 +98,7 @@ struct fw_cdev_event_iso_interrupt {
 #define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IO('#', 0x04)
 #define FW_CDEV_IOC_QUEUE_ISO          _IO('#', 0x05)
 #define FW_CDEV_IOC_START_ISO          _IO('#', 0x06)
+#define FW_CDEV_IOC_STOP_ISO           _IO('#', 0x07)
 
 struct fw_cdev_get_config_rom {
        __u32 length;
index d84792fe619a850fb42db824bd4edd99436a8ce5..1605e11572372f32645c3e547a820987ebea6b1a 100644 (file)
@@ -155,3 +155,10 @@ fw_iso_context_queue(struct fw_iso_context *ctx,
        return card->driver->queue_iso(ctx, packet, buffer, payload);
 }
 EXPORT_SYMBOL(fw_iso_context_queue);
+
+int
+fw_iso_context_stop(struct fw_iso_context *ctx)
+{
+       return ctx->card->driver->stop_iso(ctx);
+}
+EXPORT_SYMBOL(fw_iso_context_stop);
index faa384426a12e9201c9bb87ecf6496b3f29a9c59..c0ab868b9fe47e8ac7ef42693e16db02121c876c 100644 (file)
@@ -570,13 +570,19 @@ static void context_append(struct context *ctx,
 static void context_stop(struct context *ctx)
 {
        u32 reg;
+       int i;
 
        reg_write(ctx->ohci, control_clear(ctx->regs), CONTEXT_RUN);
+       flush_writes(ctx->ohci);
 
-       reg = reg_read(ctx->ohci, control_set(ctx->regs));
-       if (reg & CONTEXT_ACTIVE)
-               fw_notify("Tried to stop context, but it is still active "
-                         "(0x%08x).\n", reg);
+       for (i = 0; i < 10; i++) {
+               reg = reg_read(ctx->ohci, control_set(ctx->regs));
+               if ((reg & CONTEXT_ACTIVE) == 0)
+                       break;
+
+               fw_notify("context_stop: still active (0x%08x)\n", reg);
+               msleep(1);
+       }
 }
 
 static void
@@ -1379,6 +1385,25 @@ static int ohci_start_iso(struct fw_iso_context *base, s32 cycle)
        return 0;
 }
 
+static int ohci_stop_iso(struct fw_iso_context *base)
+{
+       struct fw_ohci *ohci = fw_ohci(base->card);
+       struct iso_context *ctx = container_of(base, struct iso_context, base);
+       int index;
+
+       if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+               index = ctx - ohci->it_context_list;
+               reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index);
+       } else {
+               index = ctx - ohci->ir_context_list;
+               reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index);
+       }
+       flush_writes(ohci);
+       context_stop(&ctx->context);
+
+       return 0;
+}
+
 static void ohci_free_iso_context(struct fw_iso_context *base)
 {
        struct fw_ohci *ohci = fw_ohci(base->card);
@@ -1386,22 +1411,18 @@ static void ohci_free_iso_context(struct fw_iso_context *base)
        unsigned long flags;
        int index;
 
+       ohci_stop_iso(base);
+       context_release(&ctx->context);
+
        spin_lock_irqsave(&ohci->lock, flags);
 
        if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
                index = ctx - ohci->it_context_list;
-               reg_write(ohci, OHCI1394_IsoXmitContextControlClear(index), ~0);
-               reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index);
                ohci->it_context_mask |= 1 << index;
        } else {
                index = ctx - ohci->ir_context_list;
-               reg_write(ohci, OHCI1394_IsoRcvContextControlClear(index), ~0);
-               reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index);
                ohci->ir_context_mask |= 1 << index;
        }
-       flush_writes(ohci);
-
-       context_release(&ctx->context);
 
        spin_unlock_irqrestore(&ohci->lock, flags);
 }
@@ -1595,6 +1616,7 @@ static const struct fw_card_driver ohci_driver = {
        .free_iso_context       = ohci_free_iso_context,
        .queue_iso              = ohci_queue_iso,
        .start_iso              = ohci_start_iso,
+       .stop_iso               = ohci_stop_iso,
 };
 
 static int software_reset(struct fw_ohci *ohci)
index 9ccbed80cebb0c448ca4693fa530d22cd7daa028..b2a0a030c0fda0cf317aa2be4faaf52631910bfd 100644 (file)
@@ -386,6 +386,9 @@ int
 fw_iso_context_start(struct fw_iso_context *ctx,
                    int channel, int speed, int cycle);
 
+int
+fw_iso_context_stop(struct fw_iso_context *ctx);
+
 struct fw_card_driver {
        const char *name;
 
@@ -428,6 +431,8 @@ struct fw_card_driver {
                         struct fw_iso_packet *packet,
                         struct fw_iso_buffer *buffer,
                         unsigned long payload);
+
+       int (*stop_iso)(struct fw_iso_context *ctx);
 };
 
 int