summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-02-16 17:34:42 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 22:02:59 +0100
commitb82956685aab4a9d333714300eb8a86fed6c9ab3 (patch)
treedec07ca99cb70714ec1bb3e5c53314a7a5573e73
parent69cdb7268ca2e644665dae8ea26e35ce4e96679c (diff)
downloadlwn-b82956685aab4a9d333714300eb8a86fed6c9ab3.tar.gz
lwn-b82956685aab4a9d333714300eb8a86fed6c9ab3.zip
firewire: Implement functionality to stop isochronous DMA contexts.
Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/fw-device-cdev.c7
-rw-r--r--drivers/firewire/fw-device-cdev.h1
-rw-r--r--drivers/firewire/fw-iso.c7
-rw-r--r--drivers/firewire/fw-ohci.c44
-rw-r--r--drivers/firewire/fw-transaction.h5
5 files changed, 53 insertions, 11 deletions
diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c
index b738c997ef39..1ce33d4f91a3 100644
--- a/drivers/firewire/fw-device-cdev.c
+++ b/drivers/firewire/fw-device-cdev.c
@@ -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;
}
diff --git a/drivers/firewire/fw-device-cdev.h b/drivers/firewire/fw-device-cdev.h
index ac91ce501bfe..257dc872f46d 100644
--- a/drivers/firewire/fw-device-cdev.h
+++ b/drivers/firewire/fw-device-cdev.h
@@ -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;
diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c
index d84792fe619a..1605e1157237 100644
--- a/drivers/firewire/fw-iso.c
+++ b/drivers/firewire/fw-iso.c
@@ -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);
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index faa384426a12..c0ab868b9fe4 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -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)
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index 9ccbed80cebb..b2a0a030c0fd 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -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