patch-2.4.21 linux-2.4.21/drivers/ieee1394/ieee1394_transactions.c

Next file: linux-2.4.21/drivers/ieee1394/ieee1394_transactions.h
Previous file: linux-2.4.21/drivers/ieee1394/ieee1394_hotplug.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/ieee1394/ieee1394_transactions.c linux-2.4.21/drivers/ieee1394/ieee1394_transactions.c
@@ -10,14 +10,16 @@
  */
 
 #include <linux/sched.h>
+#include <linux/bitops.h>
 #include <asm/errno.h>
-#include <asm/bitops.h>
+#include <linux/interrupt.h>
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "highlevel.h"
+#include "nodemgr.h"
 
 
 #define PREP_ASYNC_HEAD_ADDRESS(tc) \
@@ -27,15 +29,8 @@
         packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
         packet->header[2] = addr & 0xffffffff
 
-#define PREP_ASYNC_HEAD_RCODE(tc) \
-        packet->tcode = tc; \
-        packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
-                | (1 << 8) | (tc << 4); \
-        packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \
-        packet->header[2] = 0
 
-
-void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
+static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
 {
         PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
         packet->header_size = 12;
@@ -43,16 +38,7 @@
         packet->expect_response = 1;
 }
 
-void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode, 
-                              quadlet_t data)
-{
-        PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);
-        packet->header[3] = data;
-        packet->header_size = 16;
-        packet->data_size = 0;
-}
-
-void fill_async_readblock(struct hpsb_packet *packet, u64 addr, int length)
+static void fill_async_readblock(struct hpsb_packet *packet, u64 addr, int length)
 {
         PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
         packet->header[3] = length << 16;
@@ -61,20 +47,7 @@
         packet->expect_response = 1;
 }
 
-void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode, 
-                               int length)
-{
-        if (rcode != RCODE_COMPLETE) {
-                length = 0;
-        }
-
-        PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
-        packet->header[3] = length << 16;
-        packet->header_size = 16;
-        packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data)
+static void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data)
 {
         PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
         packet->header[3] = data;
@@ -83,7 +56,7 @@
         packet->expect_response = 1;
 }
 
-void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length)
+static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length)
 {
         PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
         packet->header[3] = length << 16;
@@ -92,15 +65,7 @@
         packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
 }
 
-void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
-{
-        PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
-        packet->header[2] = 0;
-        packet->header_size = 12;
-        packet->data_size = 0;
-}
-
-void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode, 
+static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode, 
                      int length)
 {
         PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
@@ -110,20 +75,7 @@
         packet->expect_response = 1;
 }
 
-void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode, 
-                          int length)
-{
-        if (rcode != RCODE_COMPLETE) {
-                length = 0;
-        }
-
-        PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE);
-        packet->header[3] = (length << 16) | extcode;
-        packet->header_size = 16;
-        packet->data_size = length;
-}
-
-void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
+static void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
                      int tag, int sync)
 {
         packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
@@ -135,7 +87,7 @@
         packet->tcode = TCODE_ISO_DATA;
 }
 
-void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data) 
+static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data) 
 { 
         packet->header[0] = data;
         packet->header[1] = ~data; 
@@ -146,11 +98,21 @@
         packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */
 }
 
+static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
+				     int channel, int tag, int sync)
+{
+	packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
+		| (TCODE_STREAM_DATA << 4) | sync;
+
+	packet->header_size = 4;
+	packet->data_size = length;
+	packet->type = hpsb_async;
+	packet->tcode = TCODE_ISO_DATA;
+}
 
 /**
- * get_tlabel - allocate a transaction label
- * @host: host to be used for transmission
- * @nodeid: the node ID of the transmission target
+ * hpsb_get_tlabel - allocate a transaction label
+ * @packet: the packet who's tlabel/tpool we set
  * @wait: whether to sleep if no tlabel is available
  *
  * Every asynchronous transaction on the 1394 bus needs a transaction label to
@@ -159,72 +121,66 @@
  * matching possible without ambiguity.
  *
  * There are 64 different tlabels, so an allocated tlabel has to be freed with
- * free_tlabel() after the transaction is complete (unless it's reused again for
+ * hpsb_free_tlabel() after the transaction is complete (unless it's reused again for
  * the same target node).
  *
- * @wait must not be set to true if you are calling from interrupt context.
+ * @wait cannot be set if in_interrupt()
  *
- * Return value: The allocated transaction label or -1 if there was no free
- * tlabel and @wait is false.
+ * Return value: Zero on success, otherwise non-zero. A non-zero return
+ * generally means there are no available tlabels.
  */
-int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait)
+int hpsb_get_tlabel(struct hpsb_packet *packet, int wait)
 {
-	int tlabel = 0;
 	unsigned long flags;
-	int found_tlabel = 0;
+	struct hpsb_tlabel_pool *tp;
+
+	tp = &packet->host->tpool[packet->node_id & NODE_MASK];
 
 	if (wait) {
-		down(&host->tlabel_count);
+		BUG_ON(in_interrupt());
+		down(&tp->count);
 	} else {
-		if (down_trylock(&host->tlabel_count)) return -1;
+		if (down_trylock(&tp->count))
+			return 1;
 	}
 
-	spin_lock_irqsave(&host->tlabel_lock, flags);
-
-	while (!found_tlabel) {
-		tlabel = host->tlabel_current;
-		if (tlabel < 32 && !(host->tlabel_pool[0] & 1 << tlabel)) {
-			host->tlabel_pool[0] |= 1 << tlabel;
-			found_tlabel = 1;
-		} else if (!(host->tlabel_pool[1] & 1 << (tlabel - 32))) {
-			host->tlabel_pool[1] |= 1 << (tlabel - 32);
-			found_tlabel = 1;
-		}
-		host->tlabel_current = (host->tlabel_current + 1) % 64;
-	}
+	spin_lock_irqsave(&tp->lock, flags);
 	
-	spin_unlock_irqrestore(&host->tlabel_lock, flags);
-
-	return tlabel;
+	packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next);
+	tp->next = (packet->tlabel + 1) % 64;
+	/* Should _never_ happen */
+	BUG_ON(test_and_set_bit(packet->tlabel, tp->pool));
+	tp->allocations++;
+	spin_unlock_irqrestore(&tp->lock, flags);
+
+	return 0;
 }
 
-/**
- * free_tlabel - free an allocated transaction label
- * @host: host to be used for transmission
- * @nodeid: the node ID of the transmission target
- * @tlabel: the transaction label to free
+/** 
+ * hpsb_free_tlabel - free an allocated transaction label
+ * @packet: packet whos tlabel/tpool needs to be cleared
  *
- * Frees the transaction label allocated with get_tlabel().  The tlabel has to
- * be freed after the transaction is complete (i.e. response was received for a
- * split transaction or packet was sent for a unified transaction).
+ * Frees the transaction label allocated with hpsb_get_tlabel().  The
+ * tlabel has to be freed after the transaction is complete (i.e. response
+ * was received for a split transaction or packet was sent for a unified
+ * transaction).
  *
  * A tlabel must not be freed twice.
  */
-void free_tlabel(struct hpsb_host *host, nodeid_t nodeid, int tlabel)
+void hpsb_free_tlabel(struct hpsb_packet *packet)
 {
         unsigned long flags;
+	struct hpsb_tlabel_pool *tp;
+	
+	tp = &packet->host->tpool[packet->node_id & NODE_MASK];
 
-        spin_lock_irqsave(&host->tlabel_lock, flags);
-
-        if (tlabel < 32) {
-                host->tlabel_pool[0] &= ~(1 << tlabel);
-        } else {
-                host->tlabel_pool[1] &= ~(1 << (tlabel-32));
-        }
+	BUG_ON(packet->tlabel > 63 || packet->tlabel < 0);
 
-        spin_unlock_irqrestore(&host->tlabel_lock, flags);
+        spin_lock_irqsave(&tp->lock, flags);
+	BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool));
+        spin_unlock_irqrestore(&tp->lock, flags);
 
-        up(&host->tlabel_count);
+	up(&tp->count);
 }
 
 
@@ -297,107 +253,144 @@
         HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
 }
 
-
-int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr, 
-                       quadlet_t *buffer, size_t length)
+struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
+					 u64 addr, size_t length)
 {
-        if (host->node_id != node) return -1;
-        return highlevel_read(host, node, buffer, addr, length);
-}
+        struct hpsb_packet *packet;
 
-struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
-                                          u64 addr)
-{
-        struct hpsb_packet *p;
+	if (length == 0)
+		return NULL;
+
+	packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
+	if (!packet)
+		return NULL;
 
-        p = alloc_hpsb_packet(0);
-        if (!p) return NULL;
+	packet->host = host;
+	packet->node_id = node;
+
+	if (hpsb_get_tlabel(packet, in_interrupt() ? 0 : 1)) {
+		free_hpsb_packet(packet);
+		return NULL;
+	}
 
-        p->host = host;
-        p->tlabel = get_tlabel(host, node, 1);
-        p->node_id = node;
-        fill_async_readquad(p, addr);
+	if (length == 4)
+		fill_async_readquad(packet, addr);
+	else
+		fill_async_readblock(packet, addr, length);
 
-        return p;
+	return packet;
 }
 
-struct hpsb_packet *hpsb_make_readbpacket(struct hpsb_host *host, nodeid_t node,
-                                          u64 addr, size_t length)
+struct hpsb_packet *hpsb_make_writepacket (struct hpsb_host *host, nodeid_t node,
+					   u64 addr, quadlet_t *buffer, size_t length)
 {
-        struct hpsb_packet *p;
-
-        p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
-        if (!p) return NULL;
+	struct hpsb_packet *packet;
 
-        p->host = host;
-        p->tlabel = get_tlabel(host, node, 1);
-        p->node_id = node;
-        fill_async_readblock(p, addr, length);
+	if (length == 0)
+		return NULL;
 
-        return p;
-}
+	packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
+	if (!packet)
+		return NULL;
 
-struct hpsb_packet *hpsb_make_writeqpacket(struct hpsb_host *host,
-                                           nodeid_t node, u64 addr,
-                                           quadlet_t data)
-{
-        struct hpsb_packet *p;
+	if (length % 4) { /* zero padding bytes */
+		packet->data[length >> 2] = 0;
+	}
+	packet->host = host;
+	packet->node_id = node;
 
-        p = alloc_hpsb_packet(0);
-        if (!p) return NULL;
+	if (hpsb_get_tlabel(packet, in_interrupt() ? 0 : 1)) {
+		free_hpsb_packet(packet);
+		return NULL;
+	}
 
-        p->host = host;
-        p->tlabel = get_tlabel(host, node, 1);
-        p->node_id = node;
-        fill_async_writequad(p, addr, data);
+	if (length == 4) {
+		fill_async_writequad(packet, addr, buffer ? *buffer : 0);
+	} else {
+		fill_async_writeblock(packet, addr, length);
+		if (buffer)
+			memcpy(packet->data, buffer, length);
+	}
 
-        return p;
+	return packet;
 }
 
-struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
-                                           nodeid_t node, u64 addr,
-                                           size_t length)
+struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
+                                         u64 addr, int extcode, quadlet_t *data,
+					 quadlet_t arg)
 {
-        struct hpsb_packet *p;
+	struct hpsb_packet *p;
+	u32 length;
 
-        p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
-        if (!p) return NULL;
+	p = alloc_hpsb_packet(8);
+	if (!p) return NULL;
 
-        if (length % 4) {
-                p->data[length / 4] = 0;
-        }
+	p->host = host;
+	p->node_id = node;
+	if (hpsb_get_tlabel(p, in_interrupt() ? 0 : 1)) {
+		free_hpsb_packet(p);
+		return NULL;
+	}
 
-        p->host = host;
-        p->tlabel = get_tlabel(host, node, 1);
-        p->node_id = node;
-        fill_async_writeblock(p, addr, length);
+	switch (extcode) {
+	case EXTCODE_FETCH_ADD:
+	case EXTCODE_LITTLE_ADD:
+		length = 4;
+		if (data)
+			p->data[0] = *data;
+		break;
+	default:
+		length = 8;
+		if (data) {
+			p->data[0] = arg;
+			p->data[1] = *data;
+		}
+		break;
+	}
+	fill_async_lock(p, addr, extcode, length);
 
-        return p;
+	return p;
 }
 
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
-                                         u64 addr, int extcode)
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                           u64 addr, int extcode, octlet_t *data,
+					   octlet_t arg)
 {
-        struct hpsb_packet *p;
+	struct hpsb_packet *p;
+	u32 length;
 
-        p = alloc_hpsb_packet(8);
-        if (!p) return NULL;
+	p = alloc_hpsb_packet(16);
+	if (!p) return NULL;
 
-        p->host = host;
-        p->tlabel = get_tlabel(host, node, 1);
-        p->node_id = node;
-
-        switch (extcode) {
-        case EXTCODE_FETCH_ADD:
-        case EXTCODE_LITTLE_ADD:
-                fill_async_lock(p, addr, extcode, 4);
-                break;
-        default:
-                fill_async_lock(p, addr, extcode, 8);
-                break;
-        }
+	p->host = host;
+	p->node_id = node;
+	if (hpsb_get_tlabel(p, in_interrupt() ? 0 : 1)) {
+		free_hpsb_packet(p);
+		return NULL;
+	}
+
+	switch (extcode) {
+	case EXTCODE_FETCH_ADD:
+	case EXTCODE_LITTLE_ADD:
+		length = 8;
+		if (data) {
+			p->data[0] = *data >> 32;
+			p->data[1] = *data & 0xffffffff;
+		}
+		break;
+	default:
+		length = 16;
+		if (data) {
+			p->data[0] = arg >> 32;
+			p->data[1] = arg & 0xffffffff;
+			p->data[2] = *data >> 32;
+			p->data[3] = *data & 0xffffffff;
+		}
+		break;
+	}
+	fill_async_lock(p, addr, extcode, length);
 
-        return p;
+	return p;
 }
 
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
@@ -414,6 +407,23 @@
         return p; 
 }
 
+struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
+					int length, int channel,
+					int tag, int sync)
+{
+	struct hpsb_packet *p;
+
+	p = alloc_hpsb_packet(length);
+	if (!p) return NULL;
+
+	p->host = host;
+	fill_iso_packet(p, length, channel, tag, sync);
+
+	p->generation = get_hpsb_generation(host);
+
+	return p;
+}
+
 /*
  * FIXME - these functions should probably read from / write to user space to
  * avoid in kernel buffers for user space callers
@@ -425,27 +435,12 @@
         struct hpsb_packet *packet;
         int retval = 0;
         
-        if (length == 0) {
+        if (length == 0)
                 return -EINVAL;
-        }
 
-        if (host->node_id == node) {
-                switch(highlevel_read(host, node, buffer, addr, length)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
+	BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
 
-        if (length == 4) {
-                packet = hpsb_make_readqpacket(host, node, addr);
-        } else {
-                packet = hpsb_make_readbpacket(host, node, addr, length);
-        }
+	packet = hpsb_make_readpacket(host, node, addr, length);
 
         if (!packet) {
                 return -ENOMEM;
@@ -470,35 +465,12 @@
         }
 
 hpsb_read_fail:
-        free_tlabel(host, node, packet->tlabel);
+        hpsb_free_tlabel(packet);
         free_hpsb_packet(packet);
 
         return retval;
 }
 
-struct hpsb_packet *hpsb_make_packet (struct hpsb_host *host, nodeid_t node,
-				      u64 addr, quadlet_t *buffer, size_t length)
-{
-        struct hpsb_packet *packet;
-        
-        if (length == 0)
-                return NULL;
-
-        if (length == 4)
-                packet = hpsb_make_writeqpacket(host, node, addr, *buffer);
-        else
-                packet = hpsb_make_writebpacket(host, node, addr, length);
-
-        if (!packet)
-                return NULL;
-
-	/* Sometimes this may be called without data, just to allocate the
-	 * packet. */
-        if (length != 4 && buffer)
-                memcpy(packet->data, buffer, length);
-
-	return packet;
-}
 
 int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 	       u64 addr, quadlet_t *buffer, size_t length)
@@ -509,19 +481,9 @@
 	if (length == 0)
 		return -EINVAL;
 
-	if (host->node_id == node) {
-		switch(highlevel_write(host, node, node, buffer, addr, length)) {
-		case RCODE_COMPLETE:
-			return 0;
-		case RCODE_TYPE_ERROR:
-			return -EACCES;
-		case RCODE_ADDRESS_ERROR:
-		default:
-			return -EINVAL;
-		}
-	}
+	BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
 
-	packet = hpsb_make_packet (host, node, addr, buffer, length);
+	packet = hpsb_make_writepacket (host, node, addr, buffer, length);
 
 	if (!packet)
 		return -ENOMEM;
@@ -537,60 +499,24 @@
         retval = hpsb_packet_success(packet);
 
 hpsb_write_fail:
-        free_tlabel(host, node, packet->tlabel);
+        hpsb_free_tlabel(packet);
         free_hpsb_packet(packet);
 
         return retval;
 }
 
 
-/* We need a hpsb_lock64 function for the 64 bit equivalent.  Probably. */
 int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
 {
         struct hpsb_packet *packet;
-        int retval = 0, length;
-        
-        if (host->node_id == node) {
-                switch(highlevel_lock(host, node, data, addr, *data, arg,
-                                      extcode)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
+        int retval = 0;
 
-        packet = alloc_hpsb_packet(8);
-        if (!packet) {
-                return -ENOMEM;
-        }
+	BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
 
-        packet->host = host;
-        packet->tlabel = get_tlabel(host, node, 1);
-        packet->node_id = node;
-
-        switch (extcode) {
-        case EXTCODE_MASK_SWAP:
-        case EXTCODE_COMPARE_SWAP:
-        case EXTCODE_BOUNDED_ADD:
-        case EXTCODE_WRAP_ADD:
-                length = 8;
-                packet->data[0] = arg;
-                packet->data[1] = *data;
-                break;
-        case EXTCODE_FETCH_ADD:
-        case EXTCODE_LITTLE_ADD:
-                length = 4;
-                packet->data[0] = *data;
-                break;
-        default:
-                return -EINVAL;
-        }
-        fill_async_lock(packet, addr, extcode, length);
+	packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);        
+        if (!packet)
+                return -ENOMEM;
 
 	packet->generation = generation;
         if (!hpsb_send_packet(packet)) {
@@ -606,8 +532,94 @@
         }
 
 hpsb_lock_fail:
-        free_tlabel(host, node, packet->tlabel);
+        hpsb_free_tlabel(packet);
         free_hpsb_packet(packet);
 
         return retval;
 }
+
+int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+		u64 addr, int extcode, octlet_t *data, octlet_t arg)
+{
+	struct hpsb_packet *packet;
+	int retval = 0;
+
+	BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
+
+	packet = hpsb_make_lock64packet(host, node, addr, extcode, data, arg);
+	if (!packet)
+		return -ENOMEM;
+
+	packet->generation = generation;
+	if (!hpsb_send_packet(packet)) {
+		retval = -EINVAL;
+		goto hpsb_lock64_fail;
+	}
+	down(&packet->state_change);
+	down(&packet->state_change);
+	retval = hpsb_packet_success(packet);
+
+	if (retval == 0)
+		*data = (u64)packet->data[1] << 32 | packet->data[0];
+
+hpsb_lock64_fail:
+	hpsb_free_tlabel(packet);
+	free_hpsb_packet(packet);
+
+        return retval;
+}
+
+int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
+		   quadlet_t *buffer, size_t length, u32 specifier_id,
+		   unsigned int version)
+{
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	int i;
+#endif
+
+	struct hpsb_packet *packet;
+	int retval = 0;
+	u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8;
+	u8 specifier_id_lo = specifier_id & 0xff;
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG("Send GASP: channel = %d, length = %d", channel, length);
+#endif
+
+	length += 8;
+
+	packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
+	if (!packet)
+		return -ENOMEM;
+
+	if (length % 4) {
+		packet->data[length / 4] = 0;
+	}
+
+	packet->host = host;
+	fill_async_stream_packet(packet, length, channel, 3, 0);
+        
+	packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi);
+	packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff));
+
+	memcpy(&(packet->data[2]), buffer, length - 4);
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG("GASP: packet->header_size = %d", packet->header_size);
+	HPSB_DEBUG("GASP: packet->data_size = %d", packet->data_size);
+
+	for(i=0; i<(packet->data_size/4); i++)
+		HPSB_DEBUG("GASP: data[%d]: 0x%08x", i*4, be32_to_cpu(packet->data[i]));
+#endif
+
+	packet->generation = generation;
+
+	packet->no_waiter = 1;
+
+	if (!hpsb_send_packet(packet)) {
+		free_hpsb_packet(packet);
+		retval = -EINVAL;
+	}
+
+	return retval;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)