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