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>
This commit is contained in:
parent
69cdb7268c
commit
b82956685a
|
@ -514,6 +514,11 @@ static int ioctl_start_iso(struct client *client, void __user *arg)
|
||||||
request.speed, request.cycle);
|
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
|
static int
|
||||||
dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
|
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);
|
return ioctl_queue_iso(client, arg);
|
||||||
case FW_CDEV_IOC_START_ISO:
|
case FW_CDEV_IOC_START_ISO:
|
||||||
return ioctl_start_iso(client, arg);
|
return ioctl_start_iso(client, arg);
|
||||||
|
case FW_CDEV_IOC_STOP_ISO:
|
||||||
|
return ioctl_stop_iso(client, arg);
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ struct fw_cdev_event_iso_interrupt {
|
||||||
#define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IO('#', 0x04)
|
#define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IO('#', 0x04)
|
||||||
#define FW_CDEV_IOC_QUEUE_ISO _IO('#', 0x05)
|
#define FW_CDEV_IOC_QUEUE_ISO _IO('#', 0x05)
|
||||||
#define FW_CDEV_IOC_START_ISO _IO('#', 0x06)
|
#define FW_CDEV_IOC_START_ISO _IO('#', 0x06)
|
||||||
|
#define FW_CDEV_IOC_STOP_ISO _IO('#', 0x07)
|
||||||
|
|
||||||
struct fw_cdev_get_config_rom {
|
struct fw_cdev_get_config_rom {
|
||||||
__u32 length;
|
__u32 length;
|
||||||
|
|
|
@ -155,3 +155,10 @@ fw_iso_context_queue(struct fw_iso_context *ctx,
|
||||||
return card->driver->queue_iso(ctx, packet, buffer, payload);
|
return card->driver->queue_iso(ctx, packet, buffer, payload);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fw_iso_context_queue);
|
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);
|
||||||
|
|
|
@ -570,13 +570,19 @@ static void context_append(struct context *ctx,
|
||||||
static void context_stop(struct context *ctx)
|
static void context_stop(struct context *ctx)
|
||||||
{
|
{
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
int i;
|
||||||
|
|
||||||
reg_write(ctx->ohci, control_clear(ctx->regs), CONTEXT_RUN);
|
reg_write(ctx->ohci, control_clear(ctx->regs), CONTEXT_RUN);
|
||||||
|
flush_writes(ctx->ohci);
|
||||||
|
|
||||||
reg = reg_read(ctx->ohci, control_set(ctx->regs));
|
for (i = 0; i < 10; i++) {
|
||||||
if (reg & CONTEXT_ACTIVE)
|
reg = reg_read(ctx->ohci, control_set(ctx->regs));
|
||||||
fw_notify("Tried to stop context, but it is still active "
|
if ((reg & CONTEXT_ACTIVE) == 0)
|
||||||
"(0x%08x).\n", reg);
|
break;
|
||||||
|
|
||||||
|
fw_notify("context_stop: still active (0x%08x)\n", reg);
|
||||||
|
msleep(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1379,6 +1385,25 @@ static int ohci_start_iso(struct fw_iso_context *base, s32 cycle)
|
||||||
return 0;
|
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)
|
static void ohci_free_iso_context(struct fw_iso_context *base)
|
||||||
{
|
{
|
||||||
struct fw_ohci *ohci = fw_ohci(base->card);
|
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;
|
unsigned long flags;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
|
ohci_stop_iso(base);
|
||||||
|
context_release(&ctx->context);
|
||||||
|
|
||||||
spin_lock_irqsave(&ohci->lock, flags);
|
spin_lock_irqsave(&ohci->lock, flags);
|
||||||
|
|
||||||
if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
|
if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
|
||||||
index = ctx - ohci->it_context_list;
|
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;
|
ohci->it_context_mask |= 1 << index;
|
||||||
} else {
|
} else {
|
||||||
index = ctx - ohci->ir_context_list;
|
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;
|
ohci->ir_context_mask |= 1 << index;
|
||||||
}
|
}
|
||||||
flush_writes(ohci);
|
|
||||||
|
|
||||||
context_release(&ctx->context);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ohci->lock, flags);
|
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,
|
.free_iso_context = ohci_free_iso_context,
|
||||||
.queue_iso = ohci_queue_iso,
|
.queue_iso = ohci_queue_iso,
|
||||||
.start_iso = ohci_start_iso,
|
.start_iso = ohci_start_iso,
|
||||||
|
.stop_iso = ohci_stop_iso,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int software_reset(struct fw_ohci *ohci)
|
static int software_reset(struct fw_ohci *ohci)
|
||||||
|
|
|
@ -386,6 +386,9 @@ int
|
||||||
fw_iso_context_start(struct fw_iso_context *ctx,
|
fw_iso_context_start(struct fw_iso_context *ctx,
|
||||||
int channel, int speed, int cycle);
|
int channel, int speed, int cycle);
|
||||||
|
|
||||||
|
int
|
||||||
|
fw_iso_context_stop(struct fw_iso_context *ctx);
|
||||||
|
|
||||||
struct fw_card_driver {
|
struct fw_card_driver {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
@ -428,6 +431,8 @@ struct fw_card_driver {
|
||||||
struct fw_iso_packet *packet,
|
struct fw_iso_packet *packet,
|
||||||
struct fw_iso_buffer *buffer,
|
struct fw_iso_buffer *buffer,
|
||||||
unsigned long payload);
|
unsigned long payload);
|
||||||
|
|
||||||
|
int (*stop_iso)(struct fw_iso_context *ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
Loading…
Reference in New Issue