ieee1394_core.c 37.2 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7
/*
 * IEEE 1394 for Linux
 *
 * Core support: hpsb_packet management, packet handling and forwarding to
 *               highlevel or lowlevel code
 *
 * Copyright (C) 1999, 2000 Andreas E. Bombe
8
 *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
Linus Torvalds's avatar
Linus Torvalds committed
9 10 11
 *
 * This code is licensed under the GPL.  See the file COPYING in the root
 * directory of the kernel sources for details.
12 13 14 15 16 17 18 19 20
 *
 *
 * Contributions:
 *
 * Manfred Weihs <weihs@ict.tuwien.ac.at>
 *        loopback functionality in hpsb_send_packet
 *        allow highlevel drivers to disable automatic response generation
 *              and to generate responses themselves (deferred)
 *
Linus Torvalds's avatar
Linus Torvalds committed
21 22 23 24 25 26 27 28 29
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
Linus Torvalds's avatar
Linus Torvalds committed
30
#include <linux/module.h>
31
#include <linux/moduleparam.h>
32
#include <linux/bitops.h>
Ben Collins's avatar
Ben Collins committed
33
#include <linux/kdev_t.h>
34 35
#include <linux/skbuff.h>

Linus Torvalds's avatar
Linus Torvalds committed
36 37 38 39 40 41 42 43 44 45
#include <asm/byteorder.h>
#include <asm/semaphore.h>

#include "ieee1394_types.h"
#include "ieee1394.h"
#include "hosts.h"
#include "ieee1394_core.h"
#include "highlevel.h"
#include "ieee1394_transactions.h"
#include "csr.h"
Linus Torvalds's avatar
Linus Torvalds committed
46
#include "nodemgr.h"
47 48
#include "dma.h"
#include "iso.h"
49
#include "config_roms.h"
Linus Torvalds's avatar
Linus Torvalds committed
50

Linus Torvalds's avatar
Linus Torvalds committed
51 52 53 54
/*
 * Disable the nodemgr detection and config rom reading functionality.
 */
static int disable_nodemgr = 0;
55 56
module_param(disable_nodemgr, int, 0444);
MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
Ben Collins's avatar
Ben Collins committed
57

Linus Torvalds's avatar
Linus Torvalds committed
58 59 60 61
/* We are GPL, so treat us special */
MODULE_LICENSE("GPL");

/* Some globals used */
62
const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
Linus Torvalds's avatar
Linus Torvalds committed
63

64
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
Linus Torvalds's avatar
Linus Torvalds committed
65 66
static void dump_packet(const char *text, quadlet_t *data, int size)
{
67
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
68

69 70
	size /= 4;
	size = (size > 4 ? 4 : size);
Linus Torvalds's avatar
Linus Torvalds committed
71

72 73 74 75
	printk(KERN_DEBUG "ieee1394: %s", text);
	for (i = 0; i < size; i++)
		printk(" %08x", data[i]);
	printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
76
}
77 78 79
#else
#define dump_packet(x,y,z)
#endif
Linus Torvalds's avatar
Linus Torvalds committed
80

81
static void queue_packet_complete(struct hpsb_packet *packet);
Ben Collins's avatar
Ben Collins committed
82

83 84

/**
85 86 87 88
 * hpsb_set_packet_complete_task - set the task that runs when a packet
 * completes. You cannot call this more than once on a single packet
 * before it is sent.
 *
89
 * @packet: the packet whose completion we want the task added to
90 91
 * @routine: function to call
 * @data: data (if any) to pass to the above function
92
 */
93 94
void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
				   void (*routine)(void *), void *data)
95
{
96
	WARN_ON(packet->complete_routine != NULL);
97 98
	packet->complete_routine = routine;
	packet->complete_data = data;
99 100
	return;
}
Linus Torvalds's avatar
Linus Torvalds committed
101 102

/**
Ben Collins's avatar
Ben Collins committed
103
 * hpsb_alloc_packet - allocate new packet structure
Linus Torvalds's avatar
Linus Torvalds committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
 * @data_size: size of the data block to be allocated
 *
 * This function allocates, initializes and returns a new &struct hpsb_packet.
 * It can be used in interrupt context.  A header block is always included, its
 * size is big enough to contain all possible 1394 headers.  The data block is
 * only allocated when @data_size is not zero.
 *
 * For packets for which responses will be received the @data_size has to be big
 * enough to contain the response's data block since no further allocation
 * occurs at response matching time.
 *
 * The packet's generation value will be set to the current generation number
 * for ease of use.  Remember to overwrite it with your own recorded generation
 * number if you can not be sure that your code will not race with a bus reset.
 *
 * Return value: A pointer to a &struct hpsb_packet or NULL on allocation
 * failure.
 */
Ben Collins's avatar
Ben Collins committed
122
struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
Linus Torvalds's avatar
Linus Torvalds committed
123
{
124
	struct hpsb_packet *packet = NULL;
125
	struct sk_buff *skb;
Linus Torvalds's avatar
Linus Torvalds committed
126

127 128 129 130
	data_size = ((data_size + 3) & ~3);

	skb = alloc_skb(data_size + sizeof(*packet), GFP_ATOMIC);
	if (skb == NULL)
131 132
		return NULL;

133 134 135 136
	memset(skb->data, 0, data_size + sizeof(*packet));

	packet = (struct hpsb_packet *)skb->data;
	packet->skb = skb;
Linus Torvalds's avatar
Linus Torvalds committed
137

138 139 140
	packet->header = packet->embedded_header;
	packet->state = hpsb_unused;
	packet->generation = -1;
141
	INIT_LIST_HEAD(&packet->driver_list);
142 143 144
	atomic_set(&packet->refcnt, 1);

	if (data_size) {
145
		packet->data = (quadlet_t *)(skb->data + sizeof(*packet));
146 147
		packet->data_size = data_size;
	}
Linus Torvalds's avatar
Linus Torvalds committed
148

149
	return packet;
Linus Torvalds's avatar
Linus Torvalds committed
150 151 152 153
}


/**
Ben Collins's avatar
Ben Collins committed
154
 * hpsb_free_packet - free packet and data associated with it
Linus Torvalds's avatar
Linus Torvalds committed
155 156
 * @packet: packet to free (is NULL safe)
 *
157
 * This function will free packet->data and finally the packet itself.
Linus Torvalds's avatar
Linus Torvalds committed
158
 */
Ben Collins's avatar
Ben Collins committed
159
void hpsb_free_packet(struct hpsb_packet *packet)
Linus Torvalds's avatar
Linus Torvalds committed
160
{
161
	if (packet && atomic_dec_and_test(&packet->refcnt)) {
162 163
		BUG_ON(!list_empty(&packet->driver_list));
		kfree_skb(packet->skb);
164
	}
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167
}


Linus Torvalds's avatar
Linus Torvalds committed
168
int hpsb_reset_bus(struct hpsb_host *host, int type)
Linus Torvalds's avatar
Linus Torvalds committed
169
{
Linus Torvalds's avatar
Linus Torvalds committed
170
        if (!host->in_bus_reset) {
Ben Collins's avatar
Ben Collins committed
171
                host->driver->devctl(host, RESET_BUS, type);
Linus Torvalds's avatar
Linus Torvalds committed
172 173 174 175 176 177 178 179 180 181
                return 0;
        } else {
                return 1;
        }
}


int hpsb_bus_reset(struct hpsb_host *host)
{
        if (host->in_bus_reset) {
Linus Torvalds's avatar
Linus Torvalds committed
182 183
                HPSB_NOTICE("%s called while bus reset already in progress",
			    __FUNCTION__);
Linus Torvalds's avatar
Linus Torvalds committed
184 185 186 187 188 189
                return 1;
        }

        abort_requests(host);
        host->in_bus_reset = 1;
        host->irm_id = -1;
190
	host->is_irm = 0;
Linus Torvalds's avatar
Linus Torvalds committed
191
        host->busmgr_id = -1;
192 193
	host->is_busmgr = 0;
	host->is_cycmst = 0;
Linus Torvalds's avatar
Linus Torvalds committed
194 195 196 197 198 199 200 201 202 203 204
        host->node_count = 0;
        host->selfid_count = 0;

        return 0;
}


/*
 * Verify num_of_selfids SelfIDs and return number of nodes.  Return zero in
 * case verification failed.
 */
Linus Torvalds's avatar
Linus Torvalds committed
205
static int check_selfids(struct hpsb_host *host)
Linus Torvalds's avatar
Linus Torvalds committed
206 207
{
        int nodeid = -1;
Linus Torvalds's avatar
Linus Torvalds committed
208
        int rest_of_selfids = host->selfid_count;
Linus Torvalds's avatar
Linus Torvalds committed
209 210 211 212
        struct selfid *sid = (struct selfid *)host->topology_map;
        struct ext_selfid *esid;
        int esid_seq = 23;

Ben Collins's avatar
Ben Collins committed
213 214
	host->nodes_active = 0;

Linus Torvalds's avatar
Linus Torvalds committed
215 216 217 218
        while (rest_of_selfids--) {
                if (!sid->extended) {
                        nodeid++;
                        esid_seq = 0;
219

Linus Torvalds's avatar
Linus Torvalds committed
220 221 222 223 224
                        if (sid->phy_id != nodeid) {
                                HPSB_INFO("SelfIDs failed monotony check with "
                                          "%d", sid->phy_id);
                                return 0;
                        }
225

Ben Collins's avatar
Ben Collins committed
226 227 228 229 230
			if (sid->link_active) {
				host->nodes_active++;
				if (sid->contender)
					host->irm_id = LOCAL_BUS | sid->phy_id;
			}
Linus Torvalds's avatar
Linus Torvalds committed
231 232 233
                } else {
                        esid = (struct ext_selfid *)sid;

234
                        if ((esid->phy_id != nodeid)
Linus Torvalds's avatar
Linus Torvalds committed
235 236 237 238 239 240 241 242 243
                            || (esid->seq_nr != esid_seq)) {
                                HPSB_INFO("SelfIDs failed monotony check with "
                                          "%d/%d", esid->phy_id, esid->seq_nr);
                                return 0;
                        }
                        esid_seq++;
                }
                sid++;
        }
244

Linus Torvalds's avatar
Linus Torvalds committed
245 246 247 248 249 250
        esid = (struct ext_selfid *)(sid - 1);
        while (esid->extended) {
                if ((esid->porta == 0x2) || (esid->portb == 0x2)
                    || (esid->portc == 0x2) || (esid->portd == 0x2)
                    || (esid->porte == 0x2) || (esid->portf == 0x2)
                    || (esid->portg == 0x2) || (esid->porth == 0x2)) {
251 252 253
			HPSB_INFO("SelfIDs failed root check on "
				  "extended SelfID");
			return 0;
Linus Torvalds's avatar
Linus Torvalds committed
254 255 256 257 258 259
                }
                esid--;
        }

        sid = (struct selfid *)esid;
        if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) {
260 261
		HPSB_INFO("SelfIDs failed root check");
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
262 263
        }

Ben Collins's avatar
Ben Collins committed
264 265
	host->node_count = nodeid + 1;
        return 1;
Linus Torvalds's avatar
Linus Torvalds committed
266 267 268 269
}

static void build_speed_map(struct hpsb_host *host, int nodecount)
{
270 271
	u8 speedcap[nodecount];
	u8 cldcnt[nodecount];
Linus Torvalds's avatar
Linus Torvalds committed
272 273 274 275 276 277 278
        u8 *map = host->speed_map;
        struct selfid *sid;
        struct ext_selfid *esid;
        int i, j, n;

        for (i = 0; i < (nodecount * 64); i += 64) {
                for (j = 0; j < nodecount; j++) {
Ben Collins's avatar
Ben Collins committed
279
                        map[i+j] = IEEE1394_SPEED_MAX;
Linus Torvalds's avatar
Linus Torvalds committed
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
                }
        }

        for (i = 0; i < nodecount; i++) {
                cldcnt[i] = 0;
        }

        /* find direct children count and speed */
        for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
                     n = nodecount - 1;
             (void *)sid >= (void *)host->topology_map; sid--) {
                if (sid->extended) {
                        esid = (struct ext_selfid *)sid;

                        if (esid->porta == 0x3) cldcnt[n]++;
                        if (esid->portb == 0x3) cldcnt[n]++;
                        if (esid->portc == 0x3) cldcnt[n]++;
                        if (esid->portd == 0x3) cldcnt[n]++;
                        if (esid->porte == 0x3) cldcnt[n]++;
                        if (esid->portf == 0x3) cldcnt[n]++;
                        if (esid->portg == 0x3) cldcnt[n]++;
                        if (esid->porth == 0x3) cldcnt[n]++;
                } else {
                        if (sid->port0 == 0x3) cldcnt[n]++;
                        if (sid->port1 == 0x3) cldcnt[n]++;
                        if (sid->port2 == 0x3) cldcnt[n]++;

                        speedcap[n] = sid->speed;
                        n--;
                }
        }

        /* set self mapping */
Linus Torvalds's avatar
Linus Torvalds committed
313
        for (i = 0; i < nodecount; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
314 315 316 317 318 319 320 321
                map[64*i + i] = speedcap[i];
        }

        /* fix up direct children count to total children count;
         * also fix up speedcaps for sibling and parent communication */
        for (i = 1; i < nodecount; i++) {
                for (j = cldcnt[i], n = i - 1; j > 0; j--) {
                        cldcnt[i] += cldcnt[n];
322
                        speedcap[n] = min(speedcap[n], speedcap[i]);
Linus Torvalds's avatar
Linus Torvalds committed
323 324 325 326 327 328 329 330
                        n -= cldcnt[n] + 1;
                }
        }

        for (n = 0; n < nodecount; n++) {
                for (i = n - cldcnt[n]; i <= n; i++) {
                        for (j = 0; j < (n - cldcnt[n]); j++) {
                                map[j*64 + i] = map[i*64 + j] =
331
                                        min(map[i*64 + j], speedcap[n]);
Linus Torvalds's avatar
Linus Torvalds committed
332 333 334
                        }
                        for (j = n + 1; j < nodecount; j++) {
                                map[j*64 + i] = map[i*64 + j] =
335
                                        min(map[i*64 + j], speedcap[n]);
Linus Torvalds's avatar
Linus Torvalds committed
336 337 338 339 340
                        }
                }
        }
}

Linus Torvalds's avatar
Linus Torvalds committed
341

Linus Torvalds's avatar
Linus Torvalds committed
342 343 344
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
{
        if (host->in_bus_reset) {
345
                HPSB_VERBOSE("Including SelfID 0x%x", sid);
Linus Torvalds's avatar
Linus Torvalds committed
346 347
                host->topology_map[host->selfid_count++] = sid;
        } else {
Linus Torvalds's avatar
Linus Torvalds committed
348
                HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
Ben Collins's avatar
Ben Collins committed
349
			    sid, NODEID_TO_BUS(host->node_id));
Linus Torvalds's avatar
Linus Torvalds committed
350 351 352 353 354
        }
}

void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
{
Linus Torvalds's avatar
Linus Torvalds committed
355 356 357 358
	if (!host->in_bus_reset)
		HPSB_NOTICE("SelfID completion called outside of bus reset!");

        host->node_id = LOCAL_BUS | phyid;
Linus Torvalds's avatar
Linus Torvalds committed
359 360
        host->is_root = isroot;

Ben Collins's avatar
Ben Collins committed
361
        if (!check_selfids(host)) {
Linus Torvalds's avatar
Linus Torvalds committed
362 363
                if (host->reset_retries++ < 20) {
                        /* selfid stage did not complete without error */
Linus Torvalds's avatar
Linus Torvalds committed
364
                        HPSB_NOTICE("Error in SelfID stage, resetting");
Linus Torvalds's avatar
Linus Torvalds committed
365
			host->in_bus_reset = 0;
366
			/* this should work from ohci1394 now... */
Linus Torvalds's avatar
Linus Torvalds committed
367
                        hpsb_reset_bus(host, LONG_RESET);
Linus Torvalds's avatar
Linus Torvalds committed
368 369
                        return;
                } else {
Linus Torvalds's avatar
Linus Torvalds committed
370 371
                        HPSB_NOTICE("Stopping out-of-control reset loop");
                        HPSB_NOTICE("Warning - topology map and speed map will not be valid");
372
			host->reset_retries = 0;
Linus Torvalds's avatar
Linus Torvalds committed
373 374
                }
        } else {
375
		host->reset_retries = 0;
Linus Torvalds's avatar
Linus Torvalds committed
376 377 378
                build_speed_map(host, host->node_count);
        }

379 380 381
	HPSB_VERBOSE("selfid_complete called with successful SelfID stage "
		     "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);

Linus Torvalds's avatar
Linus Torvalds committed
382 383 384
        /* irm_id is kept up to date by check_selfids() */
        if (host->irm_id == host->node_id) {
                host->is_irm = 1;
385 386 387
        } else {
                host->is_busmgr = 0;
                host->is_irm = 0;
Linus Torvalds's avatar
Linus Torvalds committed
388 389
        }

390 391 392 393
        if (isroot) {
		host->driver->devctl(host, ACT_CYCLE_MASTER, 1);
		host->is_cycmst = 1;
	}
Linus Torvalds's avatar
Linus Torvalds committed
394 395
	atomic_inc(&host->generation);
	host->in_bus_reset = 0;
Linus Torvalds's avatar
Linus Torvalds committed
396 397 398 399
        highlevel_host_reset(host);
}


400
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
Linus Torvalds's avatar
Linus Torvalds committed
401 402
                      int ackcode)
{
403
	packet->ack_code = ackcode;
Linus Torvalds's avatar
Linus Torvalds committed
404

405 406 407 408 409
	if (packet->no_waiter) {
		/* must not have a tlabel allocated */
		hpsb_free_packet(packet);
		return;
	}
Linus Torvalds's avatar
Linus Torvalds committed
410

411 412
	if (ackcode != ACK_PENDING || !packet->expect_response) {
		atomic_dec(&packet->refcnt);
413
		skb_unlink(packet->skb);
414 415 416 417
		packet->state = hpsb_complete;
		queue_packet_complete(packet);
		return;
	}
Linus Torvalds's avatar
Linus Torvalds committed
418

419 420 421 422
	if (packet->state == hpsb_complete) {
		hpsb_free_packet(packet);
		return;
	}
Linus Torvalds's avatar
Linus Torvalds committed
423

424 425 426
	atomic_dec(&packet->refcnt);
	packet->state = hpsb_pending;
	packet->sendtime = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
427

428
	mod_timer(&host->timeout, jiffies + host->timeout_interval);
Linus Torvalds's avatar
Linus Torvalds committed
429 430
}

431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
/**
 * hpsb_send_phy_config - transmit a PHY configuration packet on the bus
 * @host: host that PHY config packet gets sent through
 * @rootid: root whose force_root bit should get set (-1 = don't set force_root)
 * @gapcnt: gap count value to set (-1 = don't set gap count)
 *
 * This function sends a PHY config packet on the bus through the specified host.
 *
 * Return value: 0 for success or error number otherwise.
 */
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
{
	struct hpsb_packet *packet;
	int retval = 0;

Ben Collins's avatar
Ben Collins committed
446
	if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||
447 448 449 450 451 452
	   (rootid == -1 && gapcnt == -1)) {
		HPSB_DEBUG("Invalid Parameter: rootid = %d   gapcnt = %d",
			   rootid, gapcnt);
		return -EINVAL;
	}

Ben Collins's avatar
Ben Collins committed
453
	packet = hpsb_alloc_packet(0);
454 455 456 457
	if (!packet)
		return -ENOMEM;

	packet->host = host;
Ben Collins's avatar
Ben Collins committed
458
	packet->header_size = 8;
459 460 461 462 463
	packet->data_size = 0;
	packet->expect_response = 0;
	packet->no_waiter = 0;
	packet->type = hpsb_raw;
	packet->header[0] = 0;
Ben Collins's avatar
Ben Collins committed
464
	if (rootid != -1)
465
		packet->header[0] |= rootid << 24 | 1 << 23;
Ben Collins's avatar
Ben Collins committed
466
	if (gapcnt != -1)
467 468 469 470 471 472
		packet->header[0] |= gapcnt << 16 | 1 << 22;

	packet->header[1] = ~packet->header[0];

	packet->generation = get_hpsb_generation(host);

Ben Collins's avatar
Ben Collins committed
473 474
	retval = hpsb_send_packet_and_wait(packet);
	hpsb_free_packet(packet);
475 476 477 478

	return retval;
}

Linus Torvalds's avatar
Linus Torvalds committed
479 480 481 482 483
/**
 * hpsb_send_packet - transmit a packet on the bus
 * @packet: packet to send
 *
 * The packet is sent through the host specified in the packet->host field.
Ben Collins's avatar
Ben Collins committed
484 485
 * Before sending, the packet's transmit speed is automatically determined
 * using the local speed map when it is an async, non-broadcast packet.
Linus Torvalds's avatar
Linus Torvalds committed
486 487 488 489 490
 *
 * Possibilities for failure are that host is either not initialized, in bus
 * reset, the packet's generation number doesn't match the current generation
 * number or the host reports a transmit error.
 *
Ben Collins's avatar
Ben Collins committed
491
 * Return value: 0 on success, negative errno on failure.
Linus Torvalds's avatar
Linus Torvalds committed
492 493 494
 */
int hpsb_send_packet(struct hpsb_packet *packet)
{
495
	struct hpsb_host *host = packet->host;
Linus Torvalds's avatar
Linus Torvalds committed
496

Ben Collins's avatar
Ben Collins committed
497 498 499 500 501
        if (host->is_shutdown)
		return -EINVAL;
	if (host->in_bus_reset ||
	    (packet->generation != get_hpsb_generation(host)))
                return -EAGAIN;
Linus Torvalds's avatar
Linus Torvalds committed
502

Linus Torvalds's avatar
Linus Torvalds committed
503
        packet->state = hpsb_queued;
Linus Torvalds's avatar
Linus Torvalds committed
504

505 506
	/* This just seems silly to me */
	WARN_ON(packet->no_waiter && packet->expect_response);
507

508
	if (!packet->no_waiter || packet->expect_response) {
509
		atomic_inc(&packet->refcnt);
510
		skb_queue_tail(&host->pending_packet_queue, packet->skb);
511 512
	}

513 514 515
        if (packet->node_id == host->node_id) {
		/* it is a local request, so handle it locally */

516
                quadlet_t *data;
517
                size_t size = packet->data_size + packet->header_size;
518

519
                data = kmalloc(size, GFP_ATOMIC);
520 521
                if (!data) {
                        HPSB_ERR("unable to allocate memory for concatenating header and data");
Ben Collins's avatar
Ben Collins committed
522
                        return -ENOMEM;
523 524 525 526 527
                }

                memcpy(data, packet->header, packet->header_size);

                if (packet->data_size)
528
			memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
529 530 531

                dump_packet("send packet local:", packet->header,
                            packet->header_size);
532

533
                hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
534 535 536 537
                hpsb_packet_received(host, data, size, 0);

                kfree(data);

Ben Collins's avatar
Ben Collins committed
538
                return 0;
539 540
        }

Linus Torvalds's avatar
Linus Torvalds committed
541
        if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
Linus Torvalds's avatar
Linus Torvalds committed
542
                packet->speed_code =
Ben Collins's avatar
Ben Collins committed
543 544
                        host->speed_map[NODEID_TO_NODE(host->node_id) * 64
                                       + NODEID_TO_NODE(packet->node_id)];
Linus Torvalds's avatar
Linus Torvalds committed
545 546
        }

547
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
Linus Torvalds's avatar
Linus Torvalds committed
548 549 550 551 552 553 554 555 556 557 558 559 560
        switch (packet->speed_code) {
        case 2:
                dump_packet("send packet 400:", packet->header,
                            packet->header_size);
                break;
        case 1:
                dump_packet("send packet 200:", packet->header,
                            packet->header_size);
                break;
        default:
                dump_packet("send packet 100:", packet->header,
                            packet->header_size);
        }
561
#endif
Linus Torvalds's avatar
Linus Torvalds committed
562

Ben Collins's avatar
Ben Collins committed
563
        return host->driver->transmit_packet(host, packet);
Linus Torvalds's avatar
Linus Torvalds committed
564 565
}

Ben Collins's avatar
Ben Collins committed
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
/* We could just use complete() directly as the packet complete
 * callback, but this is more typesafe, in the sense that we get a
 * compiler error if the prototype for complete() changes. */

static void complete_packet(void *data)
{
	complete((struct completion *) data);
}

int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
{
	struct completion done;
	int retval;

	init_completion(&done);
	hpsb_set_packet_complete_task(packet, complete_packet, &done);
	retval = hpsb_send_packet(packet);
	if (retval == 0)
		wait_for_completion(&done);

	return retval;
}

Linus Torvalds's avatar
Linus Torvalds committed
589 590
static void send_packet_nocare(struct hpsb_packet *packet)
{
Ben Collins's avatar
Ben Collins committed
591 592
        if (hpsb_send_packet(packet) < 0) {
                hpsb_free_packet(packet);
Linus Torvalds's avatar
Linus Torvalds committed
593 594 595 596
        }
}


597 598
static void handle_packet_response(struct hpsb_host *host, int tcode,
				   quadlet_t *data, size_t size)
Linus Torvalds's avatar
Linus Torvalds committed
599 600
{
        struct hpsb_packet *packet = NULL;
601
	struct sk_buff *skb;
Linus Torvalds's avatar
Linus Torvalds committed
602 603 604 605 606 607
        int tcode_match = 0;
        int tlabel;
        unsigned long flags;

        tlabel = (data[0] >> 10) & 0x3f;

608
	spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
609

610 611
	skb_queue_walk(&host->pending_packet_queue, skb) {
		packet = (struct hpsb_packet *)skb->data;
Linus Torvalds's avatar
Linus Torvalds committed
612 613 614 615
                if ((packet->tlabel == tlabel)
                    && (packet->node_id == (data[1] >> 16))){
                        break;
                }
616 617

		packet = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
618 619
        }

620
	if (packet == NULL) {
621
                HPSB_DEBUG("unsolicited response packet received - no tlabel match");
Linus Torvalds's avatar
Linus Torvalds committed
622
                dump_packet("contents:", data, 16);
623
		spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
624 625 626 627 628 629
                return;
        }

        switch (packet->tcode) {
        case TCODE_WRITEQ:
        case TCODE_WRITEB:
630 631 632 633
                if (tcode != TCODE_WRITE_RESPONSE)
			break;
		tcode_match = 1;
		memcpy(packet->header, data, 12);
Linus Torvalds's avatar
Linus Torvalds committed
634 635
                break;
        case TCODE_READQ:
636 637 638 639
                if (tcode != TCODE_READQ_RESPONSE)
			break;
		tcode_match = 1;
		memcpy(packet->header, data, 16);
Linus Torvalds's avatar
Linus Torvalds committed
640 641
                break;
        case TCODE_READB:
642 643 644 645 646 647
                if (tcode != TCODE_READB_RESPONSE)
			break;
		tcode_match = 1;
		BUG_ON(packet->skb->len - sizeof(*packet) < size - 16);
		memcpy(packet->header, data, 16);
		memcpy(packet->data, data + 4, size - 16);
Linus Torvalds's avatar
Linus Torvalds committed
648 649
                break;
        case TCODE_LOCK_REQUEST:
650 651 652 653 654 655 656
                if (tcode != TCODE_LOCK_RESPONSE)
			break;
		tcode_match = 1;
		size = min((size - 16), (size_t)8);
		BUG_ON(packet->skb->len - sizeof(*packet) < size);
		memcpy(packet->header, data, 16);
		memcpy(packet->data, data + 4, size);
Linus Torvalds's avatar
Linus Torvalds committed
657 658 659
                break;
        }

660
        if (!tcode_match) {
661
                HPSB_INFO("unsolicited response packet received - tcode mismatch");
Linus Torvalds's avatar
Linus Torvalds committed
662
                dump_packet("contents:", data, 16);
663
		spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
664 665 666
                return;
        }

667 668
	__skb_unlink(skb, skb->list);
	spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
669

670 671 672 673 674 675
	if (packet->state == hpsb_queued) {
		packet->sendtime = jiffies;
		packet->ack_code = ACK_PENDING;
	}

	packet->state = hpsb_complete;
676
	queue_packet_complete(packet);
Linus Torvalds's avatar
Linus Torvalds committed
677 678 679
}


Linus Torvalds's avatar
Linus Torvalds committed
680 681
static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
					       quadlet_t *data, size_t dsize)
Linus Torvalds's avatar
Linus Torvalds committed
682 683 684
{
        struct hpsb_packet *p;

Ben Collins's avatar
Ben Collins committed
685
        p = hpsb_alloc_packet(dsize);
686
        if (unlikely(p == NULL)) {
Linus Torvalds's avatar
Linus Torvalds committed
687 688 689 690
                /* FIXME - send data_error response */
                return NULL;
        }

Linus Torvalds's avatar
Linus Torvalds committed
691 692
        p->type = hpsb_async;
        p->state = hpsb_unused;
Linus Torvalds's avatar
Linus Torvalds committed
693 694 695 696 697
        p->host = host;
        p->node_id = data[1] >> 16;
        p->tlabel = (data[0] >> 10) & 0x3f;
        p->no_waiter = 1;

Linus Torvalds's avatar
Linus Torvalds committed
698 699
	p->generation = get_hpsb_generation(host);

700 701
	if (dsize % 4)
		p->data[dsize / 4] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
702 703 704 705

        return p;
}

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
#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

static 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;
}

static 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);
}

static 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;
}

static 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;
}

Linus Torvalds's avatar
Linus Torvalds committed
754 755 756 757
#define PREP_REPLY_PACKET(length) \
                packet = create_reply_packet(host, data, length); \
                if (packet == NULL) break

Linus Torvalds's avatar
Linus Torvalds committed
758 759
static void handle_incoming_packet(struct hpsb_host *host, int tcode,
				   quadlet_t *data, size_t size, int write_acked)
Linus Torvalds's avatar
Linus Torvalds committed
760 761 762
{
        struct hpsb_packet *packet;
        int length, rcode, extcode;
763
        quadlet_t buffer;
Linus Torvalds's avatar
Linus Torvalds committed
764
        nodeid_t source = data[1] >> 16;
765 766
        nodeid_t dest = data[0] >> 16;
        u16 flags = (u16) data[0];
Linus Torvalds's avatar
Linus Torvalds committed
767 768 769 770 771 772 773
        u64 addr;

        /* big FIXME - no error checking is done for an out of bounds length */

        switch (tcode) {
        case TCODE_WRITEQ:
                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
Linus Torvalds's avatar
Linus Torvalds committed
774
                rcode = highlevel_write(host, source, dest, data+3,
775
					addr, 4, flags);
Linus Torvalds's avatar
Linus Torvalds committed
776 777

                if (!write_acked
Ben Collins's avatar
Ben Collins committed
778
                    && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
779
                    && (rcode >= 0)) {
Linus Torvalds's avatar
Linus Torvalds committed
780 781 782 783 784 785 786 787 788
                        /* not a broadcast write, reply */
                        PREP_REPLY_PACKET(0);
                        fill_async_write_resp(packet, rcode);
                        send_packet_nocare(packet);
                }
                break;

        case TCODE_WRITEB:
                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
Linus Torvalds's avatar
Linus Torvalds committed
789
                rcode = highlevel_write(host, source, dest, data+4,
790
					addr, data[3]>>16, flags);
Linus Torvalds's avatar
Linus Torvalds committed
791 792

                if (!write_acked
Ben Collins's avatar
Ben Collins committed
793
                    && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
794
                    && (rcode >= 0)) {
Linus Torvalds's avatar
Linus Torvalds committed
795 796 797 798 799 800 801 802 803
                        /* not a broadcast write, reply */
                        PREP_REPLY_PACKET(0);
                        fill_async_write_resp(packet, rcode);
                        send_packet_nocare(packet);
                }
                break;

        case TCODE_READQ:
                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
804 805 806 807 808 809 810
                rcode = highlevel_read(host, source, &buffer, addr, 4, flags);

                if (rcode >= 0) {
                        PREP_REPLY_PACKET(0);
                        fill_async_readquad_resp(packet, rcode, buffer);
                        send_packet_nocare(packet);
                }
Linus Torvalds's avatar
Linus Torvalds committed
811 812 813 814 815 816 817 818
                break;

        case TCODE_READB:
                length = data[3] >> 16;
                PREP_REPLY_PACKET(length);

                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                rcode = highlevel_read(host, source, packet->data, addr,
819 820 821 822 823
                                       length, flags);

                if (rcode >= 0) {
                        fill_async_readblock_resp(packet, rcode, length);
                        send_packet_nocare(packet);
Ben Collins's avatar
Ben Collins committed
824 825
                } else {
                        hpsb_free_packet(packet);
826
                }
Linus Torvalds's avatar
Linus Torvalds committed
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
                break;

        case TCODE_LOCK_REQUEST:
                length = data[3] >> 16;
                extcode = data[3] & 0xffff;
                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];

                PREP_REPLY_PACKET(8);

                if ((extcode == 0) || (extcode >= 7)) {
                        /* let switch default handle error */
                        length = 0;
                }

                switch (length) {
                case 4:
                        rcode = highlevel_lock(host, source, packet->data, addr,
844
                                               data[4], 0, extcode,flags);
Linus Torvalds's avatar
Linus Torvalds committed
845 846 847
                        fill_async_lock_resp(packet, rcode, extcode, 4);
                        break;
                case 8:
848
                        if ((extcode != EXTCODE_FETCH_ADD)
Linus Torvalds's avatar
Linus Torvalds committed
849 850 851
                            && (extcode != EXTCODE_LITTLE_ADD)) {
                                rcode = highlevel_lock(host, source,
                                                       packet->data, addr,
852
                                                       data[5], data[4],
853
                                                       extcode, flags);
Linus Torvalds's avatar
Linus Torvalds committed
854 855 856 857 858
                                fill_async_lock_resp(packet, rcode, extcode, 4);
                        } else {
                                rcode = highlevel_lock64(host, source,
                                             (octlet_t *)packet->data, addr,
                                             *(octlet_t *)(data + 4), 0ULL,
859
                                             extcode, flags);
Linus Torvalds's avatar
Linus Torvalds committed
860 861 862 863 864 865 866
                                fill_async_lock_resp(packet, rcode, extcode, 8);
                        }
                        break;
                case 16:
                        rcode = highlevel_lock64(host, source,
                                                 (octlet_t *)packet->data, addr,
                                                 *(octlet_t *)(data + 6),
867
                                                 *(octlet_t *)(data + 4),
868
                                                 extcode, flags);
Linus Torvalds's avatar
Linus Torvalds committed
869 870 871
                        fill_async_lock_resp(packet, rcode, extcode, 8);
                        break;
                default:
872 873
                        rcode = RCODE_TYPE_ERROR;
                        fill_async_lock_resp(packet, rcode,
Linus Torvalds's avatar
Linus Torvalds committed
874 875 876
                                             extcode, 0);
                }

877 878 879
                if (rcode >= 0) {
                        send_packet_nocare(packet);
                } else {
Ben Collins's avatar
Ben Collins committed
880
                        hpsb_free_packet(packet);
881
                }
Linus Torvalds's avatar
Linus Torvalds committed
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
                break;
        }

}
#undef PREP_REPLY_PACKET


void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
                          int write_acked)
{
        int tcode;

        if (host->in_bus_reset) {
                HPSB_INFO("received packet during reset; ignoring");
                return;
        }

        dump_packet("received packet:", data, size);

        tcode = (data[0] >> 4) & 0xf;

        switch (tcode) {
        case TCODE_WRITE_RESPONSE:
        case TCODE_READQ_RESPONSE:
        case TCODE_READB_RESPONSE:
        case TCODE_LOCK_RESPONSE:
                handle_packet_response(host, tcode, data, size);
                break;

        case TCODE_WRITEQ:
        case TCODE_WRITEB:
        case TCODE_READQ:
        case TCODE_READB:
        case TCODE_LOCK_REQUEST:
                handle_incoming_packet(host, tcode, data, size, write_acked);
                break;


        case TCODE_ISO_DATA:
                highlevel_iso_receive(host, data, size);
                break;

        case TCODE_CYCLE_START:
                /* simply ignore this packet if it is passed on */
                break;

        default:
929
                HPSB_NOTICE("received packet with bogus transaction code %d",
Linus Torvalds's avatar
Linus Torvalds committed
930 931 932 933 934 935 936 937
                            tcode);
                break;
        }
}


void abort_requests(struct hpsb_host *host)
{
938 939
	struct hpsb_packet *packet;
	struct sk_buff *skb;
Linus Torvalds's avatar
Linus Torvalds committed
940

941
	host->driver->devctl(host, CANCEL_REQUESTS, 0);
Linus Torvalds's avatar
Linus Torvalds committed
942

943 944
	while ((skb = skb_dequeue(&host->pending_packet_queue)) != NULL) {
		packet = (struct hpsb_packet *)skb->data;
Linus Torvalds's avatar
Linus Torvalds committed
945

946 947
		packet->state = hpsb_complete;
		packet->ack_code = ACKX_ABORTED;
948
		queue_packet_complete(packet);
949
	}
Linus Torvalds's avatar
Linus Torvalds committed
950 951
}

952
void abort_timedouts(unsigned long __opaque)
Linus Torvalds's avatar
Linus Torvalds committed
953
{
954
	struct hpsb_host *host = (struct hpsb_host *)__opaque;
955 956 957 958
	unsigned long flags;
	struct hpsb_packet *packet;
	struct sk_buff *skb;
	unsigned long expire;
Linus Torvalds's avatar
Linus Torvalds committed
959

960
	spin_lock_irqsave(&host->csr.lock, flags);
961
	expire = host->csr.expire;
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
	spin_unlock_irqrestore(&host->csr.lock, flags);

	/* Hold the lock around this, since we aren't dequeuing all
	 * packets, just ones we need. */
	spin_lock_irqsave(&host->pending_packet_queue.lock, flags);

	while (!skb_queue_empty(&host->pending_packet_queue)) {
		skb = skb_peek(&host->pending_packet_queue);

		packet = (struct hpsb_packet *)skb->data;

		if (time_before(packet->sendtime + expire, jiffies)) {
			__skb_unlink(skb, skb->list);
			packet->state = hpsb_complete;
			packet->ack_code = ACKX_TIMEOUT;
			queue_packet_complete(packet);
		} else {
			/* Since packets are added to the tail, the oldest
			 * ones are first, always. When we get to one that
			 * isn't timed out, the rest aren't either. */
			break;
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
985

986
	if (!skb_queue_empty(&host->pending_packet_queue))
987
		mod_timer(&host->timeout, jiffies + host->timeout_interval);
988

989
	spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
990 991
}

992 993 994 995 996

/* Kernel thread and vars, which handles packets that are completed. Only
 * packets that have a "complete" function are sent here. This way, the
 * completion is run out of kernel context, and doesn't block the rest of
 * the stack. */
997
static int khpsbpkt_pid = -1, khpsbpkt_kill;
998
static DECLARE_COMPLETION(khpsbpkt_complete);
999
struct sk_buff_head hpsbpkt_queue;
1000 1001 1002 1003 1004 1005
static DECLARE_MUTEX_LOCKED(khpsbpkt_sig);


static void queue_packet_complete(struct hpsb_packet *packet)
{
	if (packet->complete_routine != NULL) {
1006
		skb_queue_tail(&hpsbpkt_queue, packet->skb);
1007 1008 1009 1010 1011 1012 1013 1014 1015

		/* Signal the kernel thread to handle this */
		up(&khpsbpkt_sig);
	}
	return;
}

static int hpsbpkt_thread(void *__hi)
{
1016 1017 1018 1019
	struct sk_buff *skb;
	struct hpsb_packet *packet;
	void (*complete_routine)(void*);
	void *complete_data;
1020 1021 1022 1023

	daemonize("khpsbpkt");

	while (!down_interruptible(&khpsbpkt_sig)) {
1024 1025 1026
		if (khpsbpkt_kill)
			break;

1027 1028 1029 1030 1031
		while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) {
			packet = (struct hpsb_packet *)skb->data;

			complete_routine = packet->complete_routine;
			complete_data = packet->complete_data;
1032 1033 1034 1035

			packet->complete_routine = packet->complete_data = NULL;

			complete_routine(complete_data);
1036 1037 1038 1039 1040
		}
	}

	complete_and_exit(&khpsbpkt_complete, 0);
}
Linus Torvalds's avatar
Linus Torvalds committed
1041

1042

Linus Torvalds's avatar
Linus Torvalds committed
1043
static int __init ieee1394_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
1044
{
1045 1046
	int i;

1047 1048
	skb_queue_head_init(&hpsbpkt_queue);

1049 1050 1051 1052 1053
	if (hpsb_init_config_roms()) {
		HPSB_ERR("Failed to initialize some config rom entries.\n");
		HPSB_ERR("Some features may not be available\n");
	}

1054 1055 1056 1057 1058 1059
	khpsbpkt_pid = kernel_thread(hpsbpkt_thread, NULL, CLONE_KERNEL);
	if (khpsbpkt_pid < 0) {
		HPSB_ERR("Failed to start hpsbpkt thread!\n");
		return -ENOMEM;
	}

1060
	devfs_mk_dir("ieee1394");
1061 1062

	if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
Linus Torvalds's avatar
Linus Torvalds committed
1063 1064 1065 1066
		HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
		return -ENODEV;
	}

Ben Collins's avatar
Ben Collins committed
1067 1068 1069
	devfs_mk_dir("ieee1394");

	bus_register(&ieee1394_bus_type);
1070 1071
	for (i = 0; fw_bus_attrs[i]; i++)
		bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
1072
	class_register(&hpsb_host_class);
Ben Collins's avatar
Ben Collins committed
1073

1074 1075
	if (init_csr())
		return -ENOMEM;
Ben Collins's avatar
Ben Collins committed
1076

Linus Torvalds's avatar
Linus Torvalds committed
1077
	if (!disable_nodemgr)
1078
		init_ieee1394_nodemgr();
Linus Torvalds's avatar
Linus Torvalds committed
1079 1080 1081
	else
		HPSB_INFO("nodemgr functionality disabled");

Linus Torvalds's avatar
Linus Torvalds committed
1082
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1083 1084
}

Linus Torvalds's avatar
Linus Torvalds committed
1085
static void __exit ieee1394_cleanup(void)
Linus Torvalds's avatar
Linus Torvalds committed
1086
{
1087 1088
	int i;

Linus Torvalds's avatar
Linus Torvalds committed
1089 1090 1091
	if (!disable_nodemgr)
		cleanup_ieee1394_nodemgr();

Linus Torvalds's avatar
Linus Torvalds committed
1092
	cleanup_csr();
Ben Collins's avatar
Ben Collins committed
1093

1094
	class_unregister(&hpsb_host_class);
1095 1096
	for (i = 0; fw_bus_attrs[i]; i++)
		bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
Ben Collins's avatar
Ben Collins committed
1097 1098
	bus_unregister(&ieee1394_bus_type);

1099
	if (khpsbpkt_pid >= 0) {
1100 1101 1102
		khpsbpkt_kill = 1;
		mb();
		up(&khpsbpkt_sig);
1103 1104 1105
		wait_for_completion(&khpsbpkt_complete);
	}

1106 1107
	hpsb_cleanup_config_roms();

1108
	unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
1109
	devfs_remove("ieee1394");
Linus Torvalds's avatar
Linus Torvalds committed
1110 1111
}

Linus Torvalds's avatar
Linus Torvalds committed
1112 1113
module_init(ieee1394_init);
module_exit(ieee1394_cleanup);
Linus Torvalds's avatar
Linus Torvalds committed
1114 1115

/* Exported symbols */
1116 1117

/** hosts.c **/
Linus Torvalds's avatar
Linus Torvalds committed
1118 1119 1120
EXPORT_SYMBOL(hpsb_alloc_host);
EXPORT_SYMBOL(hpsb_add_host);
EXPORT_SYMBOL(hpsb_remove_host);
1121
EXPORT_SYMBOL(hpsb_update_config_rom_image);
Linus Torvalds's avatar
Linus Torvalds committed
1122

1123 1124 1125
/** ieee1394_core.c **/
EXPORT_SYMBOL(hpsb_speedto_str);
EXPORT_SYMBOL(hpsb_set_packet_complete_task);
Ben Collins's avatar
Ben Collins committed
1126 1127
EXPORT_SYMBOL(hpsb_alloc_packet);
EXPORT_SYMBOL(hpsb_free_packet);
1128
EXPORT_SYMBOL(hpsb_send_phy_config);
Linus Torvalds's avatar
Linus Torvalds committed
1129
EXPORT_SYMBOL(hpsb_send_packet);
Ben Collins's avatar
Ben Collins committed
1130
EXPORT_SYMBOL(hpsb_send_packet_and_wait);
Linus Torvalds's avatar
Linus Torvalds committed
1131 1132 1133 1134 1135 1136 1137
EXPORT_SYMBOL(hpsb_reset_bus);
EXPORT_SYMBOL(hpsb_bus_reset);
EXPORT_SYMBOL(hpsb_selfid_received);
EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);

1138 1139 1140 1141 1142
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_get_tlabel);
EXPORT_SYMBOL(hpsb_free_tlabel);
EXPORT_SYMBOL(hpsb_make_readpacket);
EXPORT_SYMBOL(hpsb_make_writepacket);
1143
EXPORT_SYMBOL(hpsb_make_streampacket);
Linus Torvalds's avatar
Linus Torvalds committed
1144
EXPORT_SYMBOL(hpsb_make_lockpacket);
1145
EXPORT_SYMBOL(hpsb_make_lock64packet);
Linus Torvalds's avatar
Linus Torvalds committed
1146
EXPORT_SYMBOL(hpsb_make_phypacket);
1147
EXPORT_SYMBOL(hpsb_make_isopacket);
Linus Torvalds's avatar
Linus Torvalds committed
1148 1149 1150
EXPORT_SYMBOL(hpsb_read);
EXPORT_SYMBOL(hpsb_write);
EXPORT_SYMBOL(hpsb_lock);
1151
EXPORT_SYMBOL(hpsb_lock64);
Ben Collins's avatar
Ben Collins committed
1152
EXPORT_SYMBOL(hpsb_send_gasp);
1153
EXPORT_SYMBOL(hpsb_packet_success);
Linus Torvalds's avatar
Linus Torvalds committed
1154

1155
/** highlevel.c **/
Linus Torvalds's avatar
Linus Torvalds committed
1156 1157 1158
EXPORT_SYMBOL(hpsb_register_highlevel);
EXPORT_SYMBOL(hpsb_unregister_highlevel);
EXPORT_SYMBOL(hpsb_register_addrspace);
1159
EXPORT_SYMBOL(hpsb_unregister_addrspace);
1160
EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
Linus Torvalds's avatar
Linus Torvalds committed
1161 1162
EXPORT_SYMBOL(hpsb_listen_channel);
EXPORT_SYMBOL(hpsb_unlisten_channel);
1163
EXPORT_SYMBOL(hpsb_get_hostinfo);
1164
EXPORT_SYMBOL(hpsb_get_host_bykey);
1165 1166 1167 1168 1169 1170
EXPORT_SYMBOL(hpsb_create_hostinfo);
EXPORT_SYMBOL(hpsb_destroy_hostinfo);
EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
Linus Torvalds's avatar
Linus Torvalds committed
1171 1172 1173 1174 1175 1176 1177 1178
EXPORT_SYMBOL(highlevel_read);
EXPORT_SYMBOL(highlevel_write);
EXPORT_SYMBOL(highlevel_lock);
EXPORT_SYMBOL(highlevel_lock64);
EXPORT_SYMBOL(highlevel_add_host);
EXPORT_SYMBOL(highlevel_remove_host);
EXPORT_SYMBOL(highlevel_host_reset);

1179
/** nodemgr.c **/
Linus Torvalds's avatar
Linus Torvalds committed
1180 1181
EXPORT_SYMBOL(hpsb_guid_get_entry);
EXPORT_SYMBOL(hpsb_nodeid_get_entry);
Ben Collins's avatar
Ben Collins committed
1182 1183 1184 1185
EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_read);
EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(hpsb_node_lock);
Linus Torvalds's avatar
Linus Torvalds committed
1186 1187
EXPORT_SYMBOL(hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
1188
EXPORT_SYMBOL(ieee1394_bus_type);
Ben Collins's avatar
Ben Collins committed
1189
EXPORT_SYMBOL(nodemgr_for_each_host);
Linus Torvalds's avatar
Linus Torvalds committed
1190

1191 1192
/** csr.c **/
EXPORT_SYMBOL(hpsb_update_config_rom);
Linus Torvalds's avatar
Linus Torvalds committed
1193

1194 1195 1196 1197 1198 1199 1200
/** dma.c **/
EXPORT_SYMBOL(dma_prog_region_init);
EXPORT_SYMBOL(dma_prog_region_alloc);
EXPORT_SYMBOL(dma_prog_region_free);
EXPORT_SYMBOL(dma_region_init);
EXPORT_SYMBOL(dma_region_alloc);
EXPORT_SYMBOL(dma_region_free);
1201 1202
EXPORT_SYMBOL(dma_region_sync_for_cpu);
EXPORT_SYMBOL(dma_region_sync_for_device);
1203 1204 1205 1206 1207 1208 1209 1210
EXPORT_SYMBOL(dma_region_mmap);
EXPORT_SYMBOL(dma_region_offset_to_bus);

/** iso.c **/
EXPORT_SYMBOL(hpsb_iso_xmit_init);
EXPORT_SYMBOL(hpsb_iso_recv_init);
EXPORT_SYMBOL(hpsb_iso_xmit_start);
EXPORT_SYMBOL(hpsb_iso_recv_start);
Ben Collins's avatar
Ben Collins committed
1211 1212 1213
EXPORT_SYMBOL(hpsb_iso_recv_listen_channel);
EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel);
EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask);
1214 1215
EXPORT_SYMBOL(hpsb_iso_stop);
EXPORT_SYMBOL(hpsb_iso_shutdown);
Ben Collins's avatar
Ben Collins committed
1216 1217
EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet);
EXPORT_SYMBOL(hpsb_iso_xmit_sync);
1218 1219
EXPORT_SYMBOL(hpsb_iso_recv_release_packets);
EXPORT_SYMBOL(hpsb_iso_n_ready);
Ben Collins's avatar
Ben Collins committed
1220 1221 1222
EXPORT_SYMBOL(hpsb_iso_packet_sent);
EXPORT_SYMBOL(hpsb_iso_packet_received);
EXPORT_SYMBOL(hpsb_iso_wake);
1223
EXPORT_SYMBOL(hpsb_iso_recv_flush);
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254

/** csr1212.c **/
EXPORT_SYMBOL(csr1212_create_csr);
EXPORT_SYMBOL(csr1212_init_local_csr);
EXPORT_SYMBOL(csr1212_new_immediate);
EXPORT_SYMBOL(csr1212_new_leaf);
EXPORT_SYMBOL(csr1212_new_csr_offset);
EXPORT_SYMBOL(csr1212_new_directory);
EXPORT_SYMBOL(csr1212_associate_keyval);
EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
EXPORT_SYMBOL(csr1212_new_extended_immediate);
EXPORT_SYMBOL(csr1212_new_extended_leaf);
EXPORT_SYMBOL(csr1212_new_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_textual_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_icon_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_modifiable_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_keyword_leaf);
EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
EXPORT_SYMBOL(csr1212_disassociate_keyval);
EXPORT_SYMBOL(csr1212_release_keyval);
EXPORT_SYMBOL(csr1212_destroy_csr);
EXPORT_SYMBOL(csr1212_read);
EXPORT_SYMBOL(csr1212_generate_positions);
EXPORT_SYMBOL(csr1212_generate_layout_order);
EXPORT_SYMBOL(csr1212_fill_cache);
EXPORT_SYMBOL(csr1212_generate_csr_image);
EXPORT_SYMBOL(csr1212_parse_keyval);
EXPORT_SYMBOL(csr1212_parse_csr);
EXPORT_SYMBOL(_csr1212_read_keyval);
EXPORT_SYMBOL(_csr1212_destroy_keyval);