aboutsummaryrefslogtreecommitdiff
path: root/drivers/firewire/fw-transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/fw-transaction.c')
-rw-r--r--drivers/firewire/fw-transaction.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index fb3b77e1bb2..5394569a1c8 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -59,20 +59,52 @@
#define phy_config_root_id(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
#define phy_identifier(id) ((id) << 30)
-static void
-close_transaction(struct fw_transaction *t, struct fw_card *card, int rcode,
- u32 * payload, size_t length)
+static int
+close_transaction(struct fw_transaction *transaction,
+ struct fw_card *card, int rcode,
+ u32 *payload, size_t length)
{
+ struct fw_transaction *t;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
- card->tlabel_mask &= ~(1 << t->tlabel);
- list_del(&t->link);
+ list_for_each_entry(t, &card->transaction_list, link) {
+ if (t == transaction) {
+ list_del(&t->link);
+ card->tlabel_mask &= ~(1 << t->tlabel);
+ break;
+ }
+ }
spin_unlock_irqrestore(&card->lock, flags);
- t->callback(card, rcode, payload, length, t->callback_data);
+ if (&t->link != &card->transaction_list) {
+ t->callback(card, rcode, payload, length, t->callback_data);
+ return 0;
+ }
+
+ return -ENOENT;
}
+/* Only valid for transactions that are potentially pending (ie have
+ * been sent). */
+int
+fw_cancel_transaction(struct fw_card *card,
+ struct fw_transaction *transaction)
+{
+ /* Cancel the packet transmission if it's still queued. That
+ * will call the packet transmission callback which cancels
+ * the transaction. */
+
+ if (card->driver->cancel_packet(card, &transaction->packet) == 0)
+ return 0;
+
+ /* If the request packet has already been sent, we need to see
+ * if the transaction is still pending and remove it in that case. */
+
+ return close_transaction(transaction, card, RCODE_CANCELLED, NULL, 0);
+}
+EXPORT_SYMBOL(fw_cancel_transaction);
+
static void
transmit_complete_callback(struct fw_packet *packet,
struct fw_card *card, int status)
@@ -162,6 +194,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
packet->speed = speed;
packet->generation = generation;
+ packet->ack = 0;
}
/**
@@ -298,8 +331,14 @@ void fw_flush_transactions(struct fw_card *card)
card->tlabel_mask = 0;
spin_unlock_irqrestore(&card->lock, flags);
- list_for_each_entry_safe(t, next, &list, link)
+ list_for_each_entry_safe(t, next, &list, link) {
+ card->driver->cancel_packet(card, &t->packet);
+
+ /* At this point cancel_packet will never call the
+ * transaction callback, since we just took all the
+ * transactions out of the list. So do it here.*/
t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
+ }
}
static struct fw_address_handler *
@@ -531,6 +570,7 @@ allocate_request(struct fw_packet *p)
request->response.speed = p->speed;
request->response.timestamp = t;
request->response.generation = p->generation;
+ request->response.ack = 0;
request->response.callback = free_response_callback;
request->ack = p->ack;
request->length = length;