Blame view

drivers/firewire/core-transaction.c 34.1 KB
c781c06d1   Kristian Høgsberg   firewire: Clean u...
1
2
  /*
   * Core IEEE1394 transaction logic
3038e353c   Kristian Høgsberg   firewire: Add cor...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   *
   * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software Foundation,
   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   */
e8ca97021   Stefan Richter   firewire: clean u...
20
  #include <linux/bug.h>
2a0a25904   Stefan Richter   firewire: wait un...
21
  #include <linux/completion.h>
e8ca97021   Stefan Richter   firewire: clean u...
22
23
  #include <linux/device.h>
  #include <linux/errno.h>
77c9a5daa   Stefan Richter   firewire: reorgan...
24
  #include <linux/firewire.h>
e8ca97021   Stefan Richter   firewire: clean u...
25
26
27
  #include <linux/firewire-constants.h>
  #include <linux/fs.h>
  #include <linux/init.h>
d6053e08f   Stefan Richter   firewire: fix sma...
28
  #include <linux/idr.h>
e8ca97021   Stefan Richter   firewire: clean u...
29
  #include <linux/jiffies.h>
3038e353c   Kristian Høgsberg   firewire: Add cor...
30
  #include <linux/kernel.h>
3038e353c   Kristian Høgsberg   firewire: Add cor...
31
  #include <linux/list.h>
e8ca97021   Stefan Richter   firewire: clean u...
32
33
34
35
36
37
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/string.h>
  #include <linux/timer.h>
  #include <linux/types.h>
6ea9e7bbf   Stefan Richter   firewire: core: u...
38
  #include <linux/workqueue.h>
e8ca97021   Stefan Richter   firewire: clean u...
39
40
  
  #include <asm/byteorder.h>
3038e353c   Kristian Høgsberg   firewire: Add cor...
41

77c9a5daa   Stefan Richter   firewire: reorgan...
42
  #include "core.h"
3038e353c   Kristian Høgsberg   firewire: Add cor...
43

a77754a75   Kristian Høgsberg   firewire: Upperca...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  #define HEADER_PRI(pri)			((pri) << 0)
  #define HEADER_TCODE(tcode)		((tcode) << 4)
  #define HEADER_RETRY(retry)		((retry) << 8)
  #define HEADER_TLABEL(tlabel)		((tlabel) << 10)
  #define HEADER_DESTINATION(destination)	((destination) << 16)
  #define HEADER_SOURCE(source)		((source) << 16)
  #define HEADER_RCODE(rcode)		((rcode) << 12)
  #define HEADER_OFFSET_HIGH(offset_high)	((offset_high) << 0)
  #define HEADER_DATA_LENGTH(length)	((length) << 16)
  #define HEADER_EXTENDED_TCODE(tcode)	((tcode) << 0)
  
  #define HEADER_GET_TCODE(q)		(((q) >> 4) & 0x0f)
  #define HEADER_GET_TLABEL(q)		(((q) >> 10) & 0x3f)
  #define HEADER_GET_RCODE(q)		(((q) >> 12) & 0x0f)
  #define HEADER_GET_DESTINATION(q)	(((q) >> 16) & 0xffff)
  #define HEADER_GET_SOURCE(q)		(((q) >> 16) & 0xffff)
  #define HEADER_GET_OFFSET_HIGH(q)	(((q) >> 0) & 0xffff)
  #define HEADER_GET_DATA_LENGTH(q)	(((q) >> 16) & 0xffff)
  #define HEADER_GET_EXTENDED_TCODE(q)	(((q) >> 0) & 0xffff)
a7ea67823   Stefan Richter   firewire: don't r...
63
64
  #define HEADER_DESTINATION_IS_BROADCAST(q) \
  	(((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f))
77c9a5daa   Stefan Richter   firewire: reorgan...
65
66
67
  #define PHY_PACKET_CONFIG	0x0
  #define PHY_PACKET_LINK_ON	0x1
  #define PHY_PACKET_SELF_ID	0x2
a77754a75   Kristian Høgsberg   firewire: Upperca...
68
69
70
  #define PHY_CONFIG_GAP_COUNT(gap_count)	(((gap_count) << 16) | (1 << 22))
  #define PHY_CONFIG_ROOT_ID(node_id)	((((node_id) & 0x3f) << 24) | (1 << 23))
  #define PHY_IDENTIFIER(id)		((id) << 30)
3038e353c   Kristian Høgsberg   firewire: Add cor...
71

410cf2bd3   Clemens Ladisch   firewire: use spl...
72
73
74
75
76
77
78
79
  /* returns 0 if the split timeout handler is already running */
  static int try_cancel_split_timeout(struct fw_transaction *t)
  {
  	if (t->is_split_transaction)
  		return del_timer(&t->split_timeout_timer);
  	else
  		return 1;
  }
53dca5117   Stefan Richter   firewire: remove ...
80
  static int close_transaction(struct fw_transaction *transaction,
a38a00fde   Stefan Richter   firewire: core: d...
81
  			     struct fw_card *card, int rcode)
3038e353c   Kristian Høgsberg   firewire: Add cor...
82
  {
730c32f58   Kristian Høgsberg   firewire: Impleme...
83
  	struct fw_transaction *t;
3038e353c   Kristian Høgsberg   firewire: Add cor...
84
85
86
  	unsigned long flags;
  
  	spin_lock_irqsave(&card->lock, flags);
730c32f58   Kristian Høgsberg   firewire: Impleme...
87
88
  	list_for_each_entry(t, &card->transaction_list, link) {
  		if (t == transaction) {
410cf2bd3   Clemens Ladisch   firewire: use spl...
89
  			if (!try_cancel_split_timeout(t)) {
2222bcb76   Clemens Ladisch   firewire: core: d...
90
91
92
  				spin_unlock_irqrestore(&card->lock, flags);
  				goto timed_out;
  			}
5c40cbfef   Clemens Ladisch   firewire: core: u...
93
  			list_del_init(&t->link);
1e626fdce   Stefan Richter   firewire: core: u...
94
  			card->tlabel_mask &= ~(1ULL << t->tlabel);
730c32f58   Kristian Høgsberg   firewire: Impleme...
95
96
97
  			break;
  		}
  	}
3038e353c   Kristian Høgsberg   firewire: Add cor...
98
  	spin_unlock_irqrestore(&card->lock, flags);
730c32f58   Kristian Høgsberg   firewire: Impleme...
99
  	if (&t->link != &card->transaction_list) {
a38a00fde   Stefan Richter   firewire: core: d...
100
  		t->callback(card, rcode, NULL, 0, t->callback_data);
730c32f58   Kristian Høgsberg   firewire: Impleme...
101
102
  		return 0;
  	}
2222bcb76   Clemens Ladisch   firewire: core: d...
103
   timed_out:
730c32f58   Kristian Høgsberg   firewire: Impleme...
104
  	return -ENOENT;
3038e353c   Kristian Høgsberg   firewire: Add cor...
105
  }
c781c06d1   Kristian Høgsberg   firewire: Clean u...
106
107
108
109
  /*
   * Only valid for transactions that are potentially pending (ie have
   * been sent).
   */
53dca5117   Stefan Richter   firewire: remove ...
110
111
  int fw_cancel_transaction(struct fw_card *card,
  			  struct fw_transaction *transaction)
730c32f58   Kristian Høgsberg   firewire: Impleme...
112
  {
c781c06d1   Kristian Høgsberg   firewire: Clean u...
113
114
  	/*
  	 * Cancel the packet transmission if it's still queued.  That
730c32f58   Kristian Høgsberg   firewire: Impleme...
115
  	 * will call the packet transmission callback which cancels
c781c06d1   Kristian Høgsberg   firewire: Clean u...
116
117
  	 * the transaction.
  	 */
730c32f58   Kristian Høgsberg   firewire: Impleme...
118
119
120
  
  	if (card->driver->cancel_packet(card, &transaction->packet) == 0)
  		return 0;
c781c06d1   Kristian Høgsberg   firewire: Clean u...
121
122
123
124
  	/*
  	 * If the request packet has already been sent, we need to see
  	 * if the transaction is still pending and remove it in that case.
  	 */
730c32f58   Kristian Høgsberg   firewire: Impleme...
125

a38a00fde   Stefan Richter   firewire: core: d...
126
  	return close_transaction(transaction, card, RCODE_CANCELLED);
730c32f58   Kristian Høgsberg   firewire: Impleme...
127
128
  }
  EXPORT_SYMBOL(fw_cancel_transaction);
5c40cbfef   Clemens Ladisch   firewire: core: u...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  static void split_transaction_timeout_callback(unsigned long data)
  {
  	struct fw_transaction *t = (struct fw_transaction *)data;
  	struct fw_card *card = t->card;
  	unsigned long flags;
  
  	spin_lock_irqsave(&card->lock, flags);
  	if (list_empty(&t->link)) {
  		spin_unlock_irqrestore(&card->lock, flags);
  		return;
  	}
  	list_del(&t->link);
  	card->tlabel_mask &= ~(1ULL << t->tlabel);
  	spin_unlock_irqrestore(&card->lock, flags);
5c40cbfef   Clemens Ladisch   firewire: core: u...
143
144
  	t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
  }
410cf2bd3   Clemens Ladisch   firewire: use spl...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  static void start_split_transaction_timeout(struct fw_transaction *t,
  					    struct fw_card *card)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&card->lock, flags);
  
  	if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
  		spin_unlock_irqrestore(&card->lock, flags);
  		return;
  	}
  
  	t->is_split_transaction = true;
  	mod_timer(&t->split_timeout_timer,
  		  jiffies + card->split_timeout_jiffies);
  
  	spin_unlock_irqrestore(&card->lock, flags);
  }
53dca5117   Stefan Richter   firewire: remove ...
163
164
  static void transmit_complete_callback(struct fw_packet *packet,
  				       struct fw_card *card, int status)
3038e353c   Kristian Høgsberg   firewire: Add cor...
165
166
167
168
169
170
  {
  	struct fw_transaction *t =
  	    container_of(packet, struct fw_transaction, packet);
  
  	switch (status) {
  	case ACK_COMPLETE:
a38a00fde   Stefan Richter   firewire: core: d...
171
  		close_transaction(t, card, RCODE_COMPLETE);
3038e353c   Kristian Høgsberg   firewire: Add cor...
172
173
  		break;
  	case ACK_PENDING:
410cf2bd3   Clemens Ladisch   firewire: use spl...
174
  		start_split_transaction_timeout(t, card);
3038e353c   Kristian Høgsberg   firewire: Add cor...
175
176
177
178
  		break;
  	case ACK_BUSY_X:
  	case ACK_BUSY_A:
  	case ACK_BUSY_B:
a38a00fde   Stefan Richter   firewire: core: d...
179
  		close_transaction(t, card, RCODE_BUSY);
3038e353c   Kristian Høgsberg   firewire: Add cor...
180
181
  		break;
  	case ACK_DATA_ERROR:
a38a00fde   Stefan Richter   firewire: core: d...
182
  		close_transaction(t, card, RCODE_DATA_ERROR);
e5f49c3b8   Kristian Høgsberg   firewire: Sanitiz...
183
  		break;
3038e353c   Kristian Høgsberg   firewire: Add cor...
184
  	case ACK_TYPE_ERROR:
a38a00fde   Stefan Richter   firewire: core: d...
185
  		close_transaction(t, card, RCODE_TYPE_ERROR);
3038e353c   Kristian Høgsberg   firewire: Add cor...
186
187
  		break;
  	default:
c781c06d1   Kristian Høgsberg   firewire: Clean u...
188
189
190
191
  		/*
  		 * In this case the ack is really a juju specific
  		 * rcode, so just forward that to the callback.
  		 */
a38a00fde   Stefan Richter   firewire: core: d...
192
  		close_transaction(t, card, status);
3038e353c   Kristian Høgsberg   firewire: Add cor...
193
194
195
  		break;
  	}
  }
53dca5117   Stefan Richter   firewire: remove ...
196
  static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
b9549bc68   Stefan Richter   firewire: small f...
197
  		int destination_id, int source_id, int generation, int speed,
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
198
  		unsigned long long offset, void *payload, size_t length)
3038e353c   Kristian Høgsberg   firewire: Add cor...
199
200
  {
  	int ext_tcode;
18e9b10fc   Stefan Richter   firewire: cdev: a...
201
202
203
204
205
206
207
208
209
210
211
  	if (tcode == TCODE_STREAM_DATA) {
  		packet->header[0] =
  			HEADER_DATA_LENGTH(length) |
  			destination_id |
  			HEADER_TCODE(TCODE_STREAM_DATA);
  		packet->header_length = 4;
  		packet->payload = payload;
  		packet->payload_length = length;
  
  		goto common;
  	}
3038e353c   Kristian Høgsberg   firewire: Add cor...
212
  	if (tcode > 0x10) {
8f9f963e5   Jarod Wilson   firewire: replace...
213
  		ext_tcode = tcode & ~0x10;
3038e353c   Kristian Høgsberg   firewire: Add cor...
214
215
216
217
218
  		tcode = TCODE_LOCK_REQUEST;
  	} else
  		ext_tcode = 0;
  
  	packet->header[0] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
219
220
221
  		HEADER_RETRY(RETRY_X) |
  		HEADER_TLABEL(tlabel) |
  		HEADER_TCODE(tcode) |
b9549bc68   Stefan Richter   firewire: small f...
222
  		HEADER_DESTINATION(destination_id);
3038e353c   Kristian Høgsberg   firewire: Add cor...
223
  	packet->header[1] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
224
  		HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
3038e353c   Kristian Høgsberg   firewire: Add cor...
225
226
227
228
229
230
231
232
233
234
235
236
237
  	packet->header[2] =
  		offset;
  
  	switch (tcode) {
  	case TCODE_WRITE_QUADLET_REQUEST:
  		packet->header[3] = *(u32 *)payload;
  		packet->header_length = 16;
  		packet->payload_length = 0;
  		break;
  
  	case TCODE_LOCK_REQUEST:
  	case TCODE_WRITE_BLOCK_REQUEST:
  		packet->header[3] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
238
239
  			HEADER_DATA_LENGTH(length) |
  			HEADER_EXTENDED_TCODE(ext_tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
240
241
242
243
244
245
246
247
248
249
250
251
  		packet->header_length = 16;
  		packet->payload = payload;
  		packet->payload_length = length;
  		break;
  
  	case TCODE_READ_QUADLET_REQUEST:
  		packet->header_length = 12;
  		packet->payload_length = 0;
  		break;
  
  	case TCODE_READ_BLOCK_REQUEST:
  		packet->header[3] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
252
253
  			HEADER_DATA_LENGTH(length) |
  			HEADER_EXTENDED_TCODE(ext_tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
254
255
256
  		packet->header_length = 16;
  		packet->payload_length = 0;
  		break;
5b189bf36   Stefan Richter   firewire: core: W...
257
258
  
  	default:
5878730be   Joe Perches   firewire: core: U...
259
260
  		WARN(1, "wrong tcode %d
  ", tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
261
  	}
18e9b10fc   Stefan Richter   firewire: cdev: a...
262
   common:
3038e353c   Kristian Høgsberg   firewire: Add cor...
263
264
  	packet->speed = speed;
  	packet->generation = generation;
730c32f58   Kristian Høgsberg   firewire: Impleme...
265
  	packet->ack = 0;
19593ffdb   Stefan Richter   firewire: ohci: 0...
266
  	packet->payload_mapped = false;
3038e353c   Kristian Høgsberg   firewire: Add cor...
267
  }
7906054f0   Clemens Ladisch   firewire: core: m...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  static int allocate_tlabel(struct fw_card *card)
  {
  	int tlabel;
  
  	tlabel = card->current_tlabel;
  	while (card->tlabel_mask & (1ULL << tlabel)) {
  		tlabel = (tlabel + 1) & 0x3f;
  		if (tlabel == card->current_tlabel)
  			return -EBUSY;
  	}
  
  	card->current_tlabel = (tlabel + 1) & 0x3f;
  	card->tlabel_mask |= 1ULL << tlabel;
  
  	return tlabel;
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
284
  /**
656b7afd4   Stefan Richter   firewire: core: f...
285
286
287
288
289
290
291
292
293
294
295
296
   * fw_send_request() - submit a request packet for transmission
   * @card:		interface to send the request at
   * @t:			transaction instance to which the request belongs
   * @tcode:		transaction code
   * @destination_id:	destination node ID, consisting of bus_ID and phy_ID
   * @generation:		bus generation in which request and response are valid
   * @speed:		transmission speed
   * @offset:		48bit wide offset into destination's address space
   * @payload:		data payload for the request subaction
   * @length:		length of the payload, in bytes
   * @callback:		function to be called when the transaction is completed
   * @callback_data:	data to be passed to the transaction completion callback
3038e353c   Kristian Høgsberg   firewire: Add cor...
297
   *
656b7afd4   Stefan Richter   firewire: core: f...
298
299
300
   * Submit a request packet into the asynchronous request transmission queue.
   * Can be called from atomic context.  If you prefer a blocking API, use
   * fw_run_transaction() in a context that can sleep.
3038e353c   Kristian Høgsberg   firewire: Add cor...
301
   *
656b7afd4   Stefan Richter   firewire: core: f...
302
303
   * In case of lock requests, specify one of the firewire-core specific %TCODE_
   * constants instead of %TCODE_LOCK_REQUEST in @tcode.
3038e353c   Kristian Høgsberg   firewire: Add cor...
304
   *
656b7afd4   Stefan Richter   firewire: core: f...
305
306
   * Make sure that the value in @destination_id is not older than the one in
   * @generation.  Otherwise the request is in danger to be sent to a wrong node.
3038e353c   Kristian Høgsberg   firewire: Add cor...
307
   *
656b7afd4   Stefan Richter   firewire: core: f...
308
   * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller
18e9b10fc   Stefan Richter   firewire: cdev: a...
309
   * needs to synthesize @destination_id with fw_stream_packet_destination_id().
656b7afd4   Stefan Richter   firewire: core: f...
310
311
312
   * It will contain tag, channel, and sy data instead of a node ID then.
   *
   * The payload buffer at @data is going to be DMA-mapped except in case of
f30e6d3e4   Stefan Richter   firewire: octlet ...
313
314
   * @length <= 8 or of local (loopback) requests.  Hence make sure that the
   * buffer complies with the restrictions of the streaming DMA mapping API.
656b7afd4   Stefan Richter   firewire: core: f...
315
316
317
318
319
320
321
   * @payload must not be freed before the @callback is called.
   *
   * In case of request types without payload, @data is NULL and @length is 0.
   *
   * After the transaction is completed successfully or unsuccessfully, the
   * @callback will be called.  Among its parameters is the response code which
   * is either one of the rcodes per IEEE 1394 or, in case of internal errors,
18d0cdfd1   Stefan Richter   firewire: normali...
322
323
324
325
   * the firewire-core specific %RCODE_SEND_ERROR.  The other firewire-core
   * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION,
   * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request
   * generation, or missing ACK respectively.
656b7afd4   Stefan Richter   firewire: core: f...
326
327
328
329
330
   *
   * Note some timing corner cases:  fw_send_request() may complete much earlier
   * than when the request packet actually hits the wire.  On the other hand,
   * transaction completion and hence execution of @callback may happen even
   * before fw_send_request() returns.
3038e353c   Kristian Høgsberg   firewire: Add cor...
331
   */
53dca5117   Stefan Richter   firewire: remove ...
332
333
334
335
  void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
  		     int destination_id, int generation, int speed,
  		     unsigned long long offset, void *payload, size_t length,
  		     fw_transaction_callback_t callback, void *callback_data)
3038e353c   Kristian Høgsberg   firewire: Add cor...
336
337
  {
  	unsigned long flags;
b9549bc68   Stefan Richter   firewire: small f...
338
  	int tlabel;
3038e353c   Kristian Høgsberg   firewire: Add cor...
339

c781c06d1   Kristian Høgsberg   firewire: Clean u...
340
  	/*
c781c06d1   Kristian Høgsberg   firewire: Clean u...
341
342
343
  	 * Allocate tlabel from the bitmap and put the transaction on
  	 * the list while holding the card spinlock.
  	 */
3038e353c   Kristian Høgsberg   firewire: Add cor...
344
345
  
  	spin_lock_irqsave(&card->lock, flags);
7906054f0   Clemens Ladisch   firewire: core: m...
346
347
  	tlabel = allocate_tlabel(card);
  	if (tlabel < 0) {
3038e353c   Kristian Høgsberg   firewire: Add cor...
348
349
350
351
  		spin_unlock_irqrestore(&card->lock, flags);
  		callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
  		return;
  	}
1e119fa99   Jay Fenlason   firewire: fw_send...
352
  	t->node_id = destination_id;
3038e353c   Kristian Høgsberg   firewire: Add cor...
353
  	t->tlabel = tlabel;
5c40cbfef   Clemens Ladisch   firewire: core: u...
354
  	t->card = card;
410cf2bd3   Clemens Ladisch   firewire: use spl...
355
  	t->is_split_transaction = false;
5c40cbfef   Clemens Ladisch   firewire: core: u...
356
357
  	setup_timer(&t->split_timeout_timer,
  		    split_transaction_timeout_callback, (unsigned long)t);
3038e353c   Kristian Høgsberg   firewire: Add cor...
358
359
  	t->callback = callback;
  	t->callback_data = callback_data;
1e119fa99   Jay Fenlason   firewire: fw_send...
360
361
362
  	fw_fill_request(&t->packet, tcode, t->tlabel,
  			destination_id, card->node_id, generation,
  			speed, offset, payload, length);
3038e353c   Kristian Høgsberg   firewire: Add cor...
363
  	t->packet.callback = transmit_complete_callback;
e9aeb46c9   Stefan Richter   firewire: fully i...
364
365
366
  	list_add_tail(&t->link, &card->transaction_list);
  
  	spin_unlock_irqrestore(&card->lock, flags);
3038e353c   Kristian Høgsberg   firewire: Add cor...
367
368
369
  	card->driver->send_request(card, &t->packet);
  }
  EXPORT_SYMBOL(fw_send_request);
1e119fa99   Jay Fenlason   firewire: fw_send...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  struct transaction_callback_data {
  	struct completion done;
  	void *payload;
  	int rcode;
  };
  
  static void transaction_callback(struct fw_card *card, int rcode,
  				 void *payload, size_t length, void *data)
  {
  	struct transaction_callback_data *d = data;
  
  	if (rcode == RCODE_COMPLETE)
  		memcpy(d->payload, payload, length);
  	d->rcode = rcode;
  	complete(&d->done);
  }
  
  /**
656b7afd4   Stefan Richter   firewire: core: f...
388
   * fw_run_transaction() - send request and sleep until transaction is completed
1e119fa99   Jay Fenlason   firewire: fw_send...
389
   *
656b7afd4   Stefan Richter   firewire: core: f...
390
391
   * Returns the RCODE.  See fw_send_request() for parameter documentation.
   * Unlike fw_send_request(), @data points to the payload of the request or/and
f30e6d3e4   Stefan Richter   firewire: octlet ...
392
393
   * to the payload of the response.  DMA mapping restrictions apply to outbound
   * request payloads of >= 8 bytes but not to inbound response payloads.
1e119fa99   Jay Fenlason   firewire: fw_send...
394
395
   */
  int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
53dca5117   Stefan Richter   firewire: remove ...
396
  		       int generation, int speed, unsigned long long offset,
ba27e1f7b   Stefan Richter   firewire: core: n...
397
  		       void *payload, size_t length)
1e119fa99   Jay Fenlason   firewire: fw_send...
398
399
400
  {
  	struct transaction_callback_data d;
  	struct fw_transaction t;
5c40cbfef   Clemens Ladisch   firewire: core: u...
401
  	init_timer_on_stack(&t.split_timeout_timer);
1e119fa99   Jay Fenlason   firewire: fw_send...
402
  	init_completion(&d.done);
ba27e1f7b   Stefan Richter   firewire: core: n...
403
  	d.payload = payload;
1e119fa99   Jay Fenlason   firewire: fw_send...
404
  	fw_send_request(card, &t, tcode, destination_id, generation, speed,
ba27e1f7b   Stefan Richter   firewire: core: n...
405
  			offset, payload, length, transaction_callback, &d);
1e119fa99   Jay Fenlason   firewire: fw_send...
406
  	wait_for_completion(&d.done);
5c40cbfef   Clemens Ladisch   firewire: core: u...
407
  	destroy_timer_on_stack(&t.split_timeout_timer);
1e119fa99   Jay Fenlason   firewire: fw_send...
408
409
410
411
  
  	return d.rcode;
  }
  EXPORT_SYMBOL(fw_run_transaction);
c0220d686   Stefan Richter   firewire: avoid m...
412
413
  static DEFINE_MUTEX(phy_config_mutex);
  static DECLARE_COMPLETION(phy_config_done);
ae1e53557   Stefan Richter   firewire: deadlin...
414
415
416
  
  static void transmit_phy_packet_callback(struct fw_packet *packet,
  					 struct fw_card *card, int status)
3038e353c   Kristian Høgsberg   firewire: Add cor...
417
  {
c0220d686   Stefan Richter   firewire: avoid m...
418
  	complete(&phy_config_done);
3038e353c   Kristian Høgsberg   firewire: Add cor...
419
  }
c0220d686   Stefan Richter   firewire: avoid m...
420
  static struct fw_packet phy_config_packet = {
5b06db166   Clemens Ladisch   firewire: make PH...
421
422
  	.header_length	= 12,
  	.header[0]	= TCODE_LINK_INTERNAL << 4,
c0220d686   Stefan Richter   firewire: avoid m...
423
424
425
426
  	.payload_length	= 0,
  	.speed		= SCODE_100,
  	.callback	= transmit_phy_packet_callback,
  };
83db801ce   Kristian Høgsberg   firewire: Impleme...
427
428
  void fw_send_phy_config(struct fw_card *card,
  			int node_id, int generation, int gap_count)
3038e353c   Kristian Høgsberg   firewire: Add cor...
429
  {
ae1e53557   Stefan Richter   firewire: deadlin...
430
  	long timeout = DIV_ROUND_UP(HZ, 10);
02d37bed1   Stefan Richter   firewire: core: i...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  	u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG);
  
  	if (node_id != FW_PHY_CONFIG_NO_NODE_ID)
  		data |= PHY_CONFIG_ROOT_ID(node_id);
  
  	if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) {
  		gap_count = card->driver->read_phy_reg(card, 1);
  		if (gap_count < 0)
  			return;
  
  		gap_count &= 63;
  		if (gap_count == 63)
  			return;
  	}
  	data |= PHY_CONFIG_GAP_COUNT(gap_count);
2a0a25904   Stefan Richter   firewire: wait un...
446

c0220d686   Stefan Richter   firewire: avoid m...
447
  	mutex_lock(&phy_config_mutex);
5b06db166   Clemens Ladisch   firewire: make PH...
448
449
  	phy_config_packet.header[1] = data;
  	phy_config_packet.header[2] = ~data;
c0220d686   Stefan Richter   firewire: avoid m...
450
451
452
453
454
  	phy_config_packet.generation = generation;
  	INIT_COMPLETION(phy_config_done);
  
  	card->driver->send_request(card, &phy_config_packet);
  	wait_for_completion_timeout(&phy_config_done, timeout);
ae1e53557   Stefan Richter   firewire: deadlin...
455

c0220d686   Stefan Richter   firewire: avoid m...
456
  	mutex_unlock(&phy_config_mutex);
3038e353c   Kristian Høgsberg   firewire: Add cor...
457
  }
53dca5117   Stefan Richter   firewire: remove ...
458
459
  static struct fw_address_handler *lookup_overlapping_address_handler(
  	struct list_head *list, unsigned long long offset, size_t length)
3038e353c   Kristian Høgsberg   firewire: Add cor...
460
461
462
463
464
465
466
467
468
469
470
  {
  	struct fw_address_handler *handler;
  
  	list_for_each_entry(handler, list, link) {
  		if (handler->offset < offset + length &&
  		    offset < handler->offset + handler->length)
  			return handler;
  	}
  
  	return NULL;
  }
db5d247ae   Clemens Ladisch   firewire: fix use...
471
472
473
474
475
476
  static bool is_enclosing_handler(struct fw_address_handler *handler,
  				 unsigned long long offset, size_t length)
  {
  	return handler->offset <= offset &&
  		offset + length <= handler->offset + handler->length;
  }
53dca5117   Stefan Richter   firewire: remove ...
477
478
  static struct fw_address_handler *lookup_enclosing_address_handler(
  	struct list_head *list, unsigned long long offset, size_t length)
3038e353c   Kristian Høgsberg   firewire: Add cor...
479
480
481
482
  {
  	struct fw_address_handler *handler;
  
  	list_for_each_entry(handler, list, link) {
db5d247ae   Clemens Ladisch   firewire: fix use...
483
  		if (is_enclosing_handler(handler, offset, length))
3038e353c   Kristian Høgsberg   firewire: Add cor...
484
485
486
487
488
489
490
491
  			return handler;
  	}
  
  	return NULL;
  }
  
  static DEFINE_SPINLOCK(address_handler_lock);
  static LIST_HEAD(address_handler_list);
21ebcd122   Stefan Richter   firewire: mark so...
492
  const struct fw_address_region fw_high_memory_region =
5af4e5eab   Stefan Richter   firewire: comma a...
493
  	{ .start = 0x000100000000ULL, .end = 0xffffe0000000ULL,  };
db8be076c   Adrian Bunk   firewire: cleanups
494
495
496
497
498
  EXPORT_SYMBOL(fw_high_memory_region);
  
  #if 0
  const struct fw_address_region fw_low_memory_region =
  	{ .start = 0x000000000000ULL, .end = 0x000100000000ULL,  };
21ebcd122   Stefan Richter   firewire: mark so...
499
  const struct fw_address_region fw_private_region =
5af4e5eab   Stefan Richter   firewire: comma a...
500
  	{ .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL,  };
21ebcd122   Stefan Richter   firewire: mark so...
501
  const struct fw_address_region fw_csr_region =
cca609771   Jarod Wilson   firewire: replace...
502
503
  	{ .start = CSR_REGISTER_BASE,
  	  .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END,  };
21ebcd122   Stefan Richter   firewire: mark so...
504
  const struct fw_address_region fw_unit_space_region =
5af4e5eab   Stefan Richter   firewire: comma a...
505
  	{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
db8be076c   Adrian Bunk   firewire: cleanups
506
  #endif  /*  0  */
3038e353c   Kristian Høgsberg   firewire: Add cor...
507

db5d247ae   Clemens Ladisch   firewire: fix use...
508
509
510
511
512
  static bool is_in_fcp_region(u64 offset, size_t length)
  {
  	return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
  		offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
513
  /**
656b7afd4   Stefan Richter   firewire: core: f...
514
515
516
   * fw_core_add_address_handler() - register for incoming requests
   * @handler:	callback
   * @region:	region in the IEEE 1212 node space address range
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
517
518
519
520
521
522
   *
   * region->start, ->end, and handler->length have to be quadlet-aligned.
   *
   * When a request is received that falls within the specified address range,
   * the specified callback is invoked.  The parameters passed to the callback
   * give the details of the particular request.
1415d9189   Stefan Richter   firewire: optimiz...
523
524
   *
   * Return value:  0 on success, non-zero otherwise.
db5d247ae   Clemens Ladisch   firewire: fix use...
525
   *
1415d9189   Stefan Richter   firewire: optimiz...
526
527
   * The start offset of the handler's address region is determined by
   * fw_core_add_address_handler() and is returned in handler->offset.
db5d247ae   Clemens Ladisch   firewire: fix use...
528
529
   *
   * Address allocations are exclusive, except for the FCP registers.
3038e353c   Kristian Høgsberg   firewire: Add cor...
530
   */
53dca5117   Stefan Richter   firewire: remove ...
531
532
  int fw_core_add_address_handler(struct fw_address_handler *handler,
  				const struct fw_address_region *region)
3038e353c   Kristian Høgsberg   firewire: Add cor...
533
534
535
536
  {
  	struct fw_address_handler *other;
  	unsigned long flags;
  	int ret = -EBUSY;
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
537
  	if (region->start & 0xffff000000000003ULL ||
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
538
  	    region->start >= region->end ||
0c9ae701a   Stefan Richter   firewire: core: f...
539
  	    region->end   > 0x0001000000000000ULL ||
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
540
541
542
  	    handler->length & 3 ||
  	    handler->length == 0)
  		return -EINVAL;
3038e353c   Kristian Høgsberg   firewire: Add cor...
543
  	spin_lock_irqsave(&address_handler_lock, flags);
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
544
  	handler->offset = region->start;
3038e353c   Kristian Høgsberg   firewire: Add cor...
545
  	while (handler->offset + handler->length <= region->end) {
db5d247ae   Clemens Ladisch   firewire: fix use...
546
547
548
549
550
551
  		if (is_in_fcp_region(handler->offset, handler->length))
  			other = NULL;
  		else
  			other = lookup_overlapping_address_handler
  					(&address_handler_list,
  					 handler->offset, handler->length);
3038e353c   Kristian Høgsberg   firewire: Add cor...
552
  		if (other != NULL) {
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
553
  			handler->offset += other->length;
3038e353c   Kristian Høgsberg   firewire: Add cor...
554
555
556
557
558
559
560
561
562
563
564
  		} else {
  			list_add_tail(&handler->link, &address_handler_list);
  			ret = 0;
  			break;
  		}
  	}
  
  	spin_unlock_irqrestore(&address_handler_lock, flags);
  
  	return ret;
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
565
566
567
  EXPORT_SYMBOL(fw_core_add_address_handler);
  
  /**
656b7afd4   Stefan Richter   firewire: core: f...
568
   * fw_core_remove_address_handler() - unregister an address handler
3038e353c   Kristian Høgsberg   firewire: Add cor...
569
   */
3038e353c   Kristian Høgsberg   firewire: Add cor...
570
571
572
573
574
575
576
577
  void fw_core_remove_address_handler(struct fw_address_handler *handler)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&address_handler_lock, flags);
  	list_del(&handler->link);
  	spin_unlock_irqrestore(&address_handler_lock, flags);
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
578
579
580
581
  EXPORT_SYMBOL(fw_core_remove_address_handler);
  
  struct fw_request {
  	struct fw_packet response;
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
582
  	u32 request_header[4];
3038e353c   Kristian Høgsberg   firewire: Add cor...
583
584
585
586
  	int ack;
  	u32 length;
  	u32 data[0];
  };
53dca5117   Stefan Richter   firewire: remove ...
587
588
  static void free_response_callback(struct fw_packet *packet,
  				   struct fw_card *card, int status)
3038e353c   Kristian Høgsberg   firewire: Add cor...
589
590
591
592
593
594
  {
  	struct fw_request *request;
  
  	request = container_of(packet, struct fw_request, response);
  	kfree(request);
  }
a10c0ce76   Clemens Ladisch   firewire: check c...
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
  int fw_get_response_length(struct fw_request *r)
  {
  	int tcode, ext_tcode, data_length;
  
  	tcode = HEADER_GET_TCODE(r->request_header[0]);
  
  	switch (tcode) {
  	case TCODE_WRITE_QUADLET_REQUEST:
  	case TCODE_WRITE_BLOCK_REQUEST:
  		return 0;
  
  	case TCODE_READ_QUADLET_REQUEST:
  		return 4;
  
  	case TCODE_READ_BLOCK_REQUEST:
  		data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
  		return data_length;
  
  	case TCODE_LOCK_REQUEST:
  		ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]);
  		data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
  		switch (ext_tcode) {
  		case EXTCODE_FETCH_ADD:
  		case EXTCODE_LITTLE_ADD:
  			return data_length;
  		default:
  			return data_length / 2;
  		}
  
  	default:
5878730be   Joe Perches   firewire: core: U...
625
626
  		WARN(1, "wrong tcode %d
  ", tcode);
a10c0ce76   Clemens Ladisch   firewire: check c...
627
628
629
  		return 0;
  	}
  }
53dca5117   Stefan Richter   firewire: remove ...
630
631
  void fw_fill_response(struct fw_packet *response, u32 *request_header,
  		      int rcode, void *payload, size_t length)
3038e353c   Kristian Høgsberg   firewire: Add cor...
632
633
  {
  	int tcode, tlabel, extended_tcode, source, destination;
a77754a75   Kristian Høgsberg   firewire: Upperca...
634
635
636
637
638
  	tcode          = HEADER_GET_TCODE(request_header[0]);
  	tlabel         = HEADER_GET_TLABEL(request_header[0]);
  	source         = HEADER_GET_DESTINATION(request_header[0]);
  	destination    = HEADER_GET_SOURCE(request_header[1]);
  	extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
639
640
  
  	response->header[0] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
641
642
643
  		HEADER_RETRY(RETRY_1) |
  		HEADER_TLABEL(tlabel) |
  		HEADER_DESTINATION(destination);
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
644
  	response->header[1] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
645
646
  		HEADER_SOURCE(source) |
  		HEADER_RCODE(rcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
647
648
649
650
651
  	response->header[2] = 0;
  
  	switch (tcode) {
  	case TCODE_WRITE_QUADLET_REQUEST:
  	case TCODE_WRITE_BLOCK_REQUEST:
a77754a75   Kristian Høgsberg   firewire: Upperca...
652
  		response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE);
3038e353c   Kristian Høgsberg   firewire: Add cor...
653
654
655
656
657
658
  		response->header_length = 12;
  		response->payload_length = 0;
  		break;
  
  	case TCODE_READ_QUADLET_REQUEST:
  		response->header[0] |=
a77754a75   Kristian Høgsberg   firewire: Upperca...
659
  			HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE);
93c4cceb9   Kristian Høgsberg   firewire: Handle ...
660
661
662
663
  		if (payload != NULL)
  			response->header[3] = *(u32 *)payload;
  		else
  			response->header[3] = 0;
3038e353c   Kristian Høgsberg   firewire: Add cor...
664
665
666
667
668
669
  		response->header_length = 16;
  		response->payload_length = 0;
  		break;
  
  	case TCODE_READ_BLOCK_REQUEST:
  	case TCODE_LOCK_REQUEST:
a77754a75   Kristian Høgsberg   firewire: Upperca...
670
  		response->header[0] |= HEADER_TCODE(tcode + 2);
3038e353c   Kristian Høgsberg   firewire: Add cor...
671
  		response->header[3] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
672
673
  			HEADER_DATA_LENGTH(length) |
  			HEADER_EXTENDED_TCODE(extended_tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
674
  		response->header_length = 16;
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
675
676
  		response->payload = payload;
  		response->payload_length = length;
3038e353c   Kristian Høgsberg   firewire: Add cor...
677
678
679
  		break;
  
  	default:
5878730be   Joe Perches   firewire: core: U...
680
681
  		WARN(1, "wrong tcode %d
  ", tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
682
  	}
1d1dc5e83   Stefan Richter   firewire: fw-ohci...
683

19593ffdb   Stefan Richter   firewire: ohci: 0...
684
  	response->payload_mapped = false;
3038e353c   Kristian Høgsberg   firewire: Add cor...
685
  }
93c4cceb9   Kristian Høgsberg   firewire: Handle ...
686
  EXPORT_SYMBOL(fw_fill_response);
3038e353c   Kristian Høgsberg   firewire: Add cor...
687

8e4b50f94   Clemens Ladisch   firewire: core: a...
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  static u32 compute_split_timeout_timestamp(struct fw_card *card,
  					   u32 request_timestamp)
  {
  	unsigned int cycles;
  	u32 timestamp;
  
  	cycles = card->split_timeout_cycles;
  	cycles += request_timestamp & 0x1fff;
  
  	timestamp = request_timestamp & ~0x1fff;
  	timestamp += (cycles / 8000) << 13;
  	timestamp |= cycles % 8000;
  
  	return timestamp;
  }
  
  static struct fw_request *allocate_request(struct fw_card *card,
  					   struct fw_packet *p)
3038e353c   Kristian Høgsberg   firewire: Add cor...
706
707
708
  {
  	struct fw_request *request;
  	u32 *data, length;
8e4b50f94   Clemens Ladisch   firewire: core: a...
709
  	int request_tcode;
3038e353c   Kristian Høgsberg   firewire: Add cor...
710

a77754a75   Kristian Høgsberg   firewire: Upperca...
711
  	request_tcode = HEADER_GET_TCODE(p->header[0]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
712
713
  	switch (request_tcode) {
  	case TCODE_WRITE_QUADLET_REQUEST:
2639a6fb2   Kristian Høgsberg   firewire: Use str...
714
  		data = &p->header[3];
3038e353c   Kristian Høgsberg   firewire: Add cor...
715
716
717
718
719
  		length = 4;
  		break;
  
  	case TCODE_WRITE_BLOCK_REQUEST:
  	case TCODE_LOCK_REQUEST:
2639a6fb2   Kristian Høgsberg   firewire: Use str...
720
  		data = p->payload;
a77754a75   Kristian Høgsberg   firewire: Upperca...
721
  		length = HEADER_GET_DATA_LENGTH(p->header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
722
723
724
725
726
727
728
729
730
  		break;
  
  	case TCODE_READ_QUADLET_REQUEST:
  		data = NULL;
  		length = 4;
  		break;
  
  	case TCODE_READ_BLOCK_REQUEST:
  		data = NULL;
a77754a75   Kristian Høgsberg   firewire: Upperca...
731
  		length = HEADER_GET_DATA_LENGTH(p->header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
732
733
734
  		break;
  
  	default:
0bf607c5b   Stefan Richter   firewire: don't p...
735
736
737
  		fw_error("ERROR - corrupt request received - %08x %08x %08x
  ",
  			 p->header[0], p->header[1], p->header[2]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
738
739
  		return NULL;
  	}
2d826cc5c   Kristian Høgsberg   firewire: Always ...
740
  	request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
3038e353c   Kristian Høgsberg   firewire: Add cor...
741
742
  	if (request == NULL)
  		return NULL;
2639a6fb2   Kristian Høgsberg   firewire: Use str...
743
  	request->response.speed = p->speed;
8e4b50f94   Clemens Ladisch   firewire: core: a...
744
745
  	request->response.timestamp =
  			compute_split_timeout_timestamp(card, p->timestamp);
2639a6fb2   Kristian Høgsberg   firewire: Use str...
746
  	request->response.generation = p->generation;
730c32f58   Kristian Høgsberg   firewire: Impleme...
747
  	request->response.ack = 0;
3038e353c   Kristian Høgsberg   firewire: Add cor...
748
  	request->response.callback = free_response_callback;
2639a6fb2   Kristian Høgsberg   firewire: Use str...
749
  	request->ack = p->ack;
93c4cceb9   Kristian Høgsberg   firewire: Handle ...
750
  	request->length = length;
3038e353c   Kristian Høgsberg   firewire: Add cor...
751
  	if (data)
6e2e8424d   Kristian Høgsberg   firewire: Use cor...
752
  		memcpy(request->data, data, length);
3038e353c   Kristian Høgsberg   firewire: Add cor...
753

2d826cc5c   Kristian Høgsberg   firewire: Always ...
754
  	memcpy(request->request_header, p->header, sizeof(p->header));
3038e353c   Kristian Høgsberg   firewire: Add cor...
755
756
757
  
  	return request;
  }
53dca5117   Stefan Richter   firewire: remove ...
758
759
  void fw_send_response(struct fw_card *card,
  		      struct fw_request *request, int rcode)
3038e353c   Kristian Høgsberg   firewire: Add cor...
760
  {
db5d247ae   Clemens Ladisch   firewire: fix use...
761
762
  	if (WARN_ONCE(!request, "invalid for FCP address handlers"))
  		return;
a7ea67823   Stefan Richter   firewire: don't r...
763
764
765
  	/* unified transaction or broadcast transaction: don't respond */
  	if (request->ack != ACK_PENDING ||
  	    HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
9c9bdf4d5   Stefan Richter   firewire: fix mem...
766
  		kfree(request);
3038e353c   Kristian Høgsberg   firewire: Add cor...
767
  		return;
9c9bdf4d5   Stefan Richter   firewire: fix mem...
768
  	}
3038e353c   Kristian Høgsberg   firewire: Add cor...
769

36bfe49d0   Kristian Høgsberg   firewire: Clean u...
770
771
  	if (rcode == RCODE_COMPLETE)
  		fw_fill_response(&request->response, request->request_header,
a10c0ce76   Clemens Ladisch   firewire: check c...
772
773
  				 rcode, request->data,
  				 fw_get_response_length(request));
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
774
775
776
  	else
  		fw_fill_response(&request->response, request->request_header,
  				 rcode, NULL, 0);
3038e353c   Kristian Høgsberg   firewire: Add cor...
777
778
779
  
  	card->driver->send_response(card, &request->response);
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
780
  EXPORT_SYMBOL(fw_send_response);
db5d247ae   Clemens Ladisch   firewire: fix use...
781
782
783
784
  static void handle_exclusive_region_request(struct fw_card *card,
  					    struct fw_packet *p,
  					    struct fw_request *request,
  					    unsigned long long offset)
3038e353c   Kristian Høgsberg   firewire: Add cor...
785
786
  {
  	struct fw_address_handler *handler;
3038e353c   Kristian Høgsberg   firewire: Add cor...
787
  	unsigned long flags;
2639a6fb2   Kristian Høgsberg   firewire: Use str...
788
  	int tcode, destination, source;
3038e353c   Kristian Høgsberg   firewire: Add cor...
789

a77754a75   Kristian Høgsberg   firewire: Upperca...
790
  	destination = HEADER_GET_DESTINATION(p->header[0]);
478b233ed   Rabin Vincent   firewire: Fix ext...
791
  	source      = HEADER_GET_SOURCE(p->header[1]);
c82f91f26   Jay Fenlason   firewire: expose ...
792
793
794
  	tcode       = HEADER_GET_TCODE(p->header[0]);
  	if (tcode == TCODE_LOCK_REQUEST)
  		tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
795
796
797
798
799
  
  	spin_lock_irqsave(&address_handler_lock, flags);
  	handler = lookup_enclosing_address_handler(&address_handler_list,
  						   offset, request->length);
  	spin_unlock_irqrestore(&address_handler_lock, flags);
c781c06d1   Kristian Høgsberg   firewire: Clean u...
800
801
  	/*
  	 * FIXME: lookup the fw_node corresponding to the sender of
3038e353c   Kristian Høgsberg   firewire: Add cor...
802
803
804
  	 * this request and pass that to the address handler instead
  	 * of the node ID.  We may also want to move the address
  	 * allocations to fw_node so we only do this callback if the
c781c06d1   Kristian Høgsberg   firewire: Clean u...
805
806
  	 * upper layers registered it for this node.
  	 */
3038e353c   Kristian Høgsberg   firewire: Add cor...
807
808
809
810
811
812
  
  	if (handler == NULL)
  		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
  	else
  		handler->address_callback(card, request,
  					  tcode, destination, source,
33e553fe2   Stefan Richter   firewire: remove ...
813
  					  p->generation, offset,
3038e353c   Kristian Høgsberg   firewire: Add cor...
814
815
816
  					  request->data, request->length,
  					  handler->callback_data);
  }
db5d247ae   Clemens Ladisch   firewire: fix use...
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
  
  static void handle_fcp_region_request(struct fw_card *card,
  				      struct fw_packet *p,
  				      struct fw_request *request,
  				      unsigned long long offset)
  {
  	struct fw_address_handler *handler;
  	unsigned long flags;
  	int tcode, destination, source;
  
  	if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
  	     offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
  	    request->length > 0x200) {
  		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
  
  		return;
  	}
  
  	tcode       = HEADER_GET_TCODE(p->header[0]);
  	destination = HEADER_GET_DESTINATION(p->header[0]);
  	source      = HEADER_GET_SOURCE(p->header[1]);
  
  	if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
  	    tcode != TCODE_WRITE_BLOCK_REQUEST) {
  		fw_send_response(card, request, RCODE_TYPE_ERROR);
  
  		return;
  	}
  
  	spin_lock_irqsave(&address_handler_lock, flags);
  	list_for_each_entry(handler, &address_handler_list, link) {
  		if (is_enclosing_handler(handler, offset, request->length))
  			handler->address_callback(card, NULL, tcode,
  						  destination, source,
33e553fe2   Stefan Richter   firewire: remove ...
851
852
  						  p->generation, offset,
  						  request->data,
db5d247ae   Clemens Ladisch   firewire: fix use...
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
  						  request->length,
  						  handler->callback_data);
  	}
  	spin_unlock_irqrestore(&address_handler_lock, flags);
  
  	fw_send_response(card, request, RCODE_COMPLETE);
  }
  
  void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
  {
  	struct fw_request *request;
  	unsigned long long offset;
  
  	if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
  		return;
bf54e1462   Stefan Richter   firewire: cdev: a...
868
869
870
871
  	if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) {
  		fw_cdev_handle_phy_packet(card, p);
  		return;
  	}
8e4b50f94   Clemens Ladisch   firewire: core: a...
872
  	request = allocate_request(card, p);
db5d247ae   Clemens Ladisch   firewire: fix use...
873
874
875
876
877
878
879
880
881
882
883
884
885
886
  	if (request == NULL) {
  		/* FIXME: send statically allocated busy packet. */
  		return;
  	}
  
  	offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) |
  		p->header[2];
  
  	if (!is_in_fcp_region(offset, request->length))
  		handle_exclusive_region_request(card, p, request, offset);
  	else
  		handle_fcp_region_request(card, p, request, offset);
  
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
887
  EXPORT_SYMBOL(fw_core_handle_request);
53dca5117   Stefan Richter   firewire: remove ...
888
  void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
3038e353c   Kristian Høgsberg   firewire: Add cor...
889
890
891
892
893
  {
  	struct fw_transaction *t;
  	unsigned long flags;
  	u32 *data;
  	size_t data_length;
ae86e81e4   Stefan Richter   firewire: core: r...
894
  	int tcode, tlabel, source, rcode;
3038e353c   Kristian Høgsberg   firewire: Add cor...
895

ae86e81e4   Stefan Richter   firewire: core: r...
896
897
898
899
  	tcode	= HEADER_GET_TCODE(p->header[0]);
  	tlabel	= HEADER_GET_TLABEL(p->header[0]);
  	source	= HEADER_GET_SOURCE(p->header[1]);
  	rcode	= HEADER_GET_RCODE(p->header[1]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
900
901
902
903
  
  	spin_lock_irqsave(&card->lock, flags);
  	list_for_each_entry(t, &card->transaction_list, link) {
  		if (t->node_id == source && t->tlabel == tlabel) {
410cf2bd3   Clemens Ladisch   firewire: use spl...
904
  			if (!try_cancel_split_timeout(t)) {
2222bcb76   Clemens Ladisch   firewire: core: d...
905
906
907
  				spin_unlock_irqrestore(&card->lock, flags);
  				goto timed_out;
  			}
5c40cbfef   Clemens Ladisch   firewire: core: u...
908
  			list_del_init(&t->link);
753a8970f   Peter Hurley   firewire: core: F...
909
  			card->tlabel_mask &= ~(1ULL << t->tlabel);
3038e353c   Kristian Høgsberg   firewire: Add cor...
910
911
912
913
914
915
  			break;
  		}
  	}
  	spin_unlock_irqrestore(&card->lock, flags);
  
  	if (&t->link == &card->transaction_list) {
2222bcb76   Clemens Ladisch   firewire: core: d...
916
   timed_out:
32b46093a   Kristian Høgsberg   firewire: Rework ...
917
918
919
  		fw_notify("Unsolicited response (source %x, tlabel %x)
  ",
  			  source, tlabel);
3038e353c   Kristian Høgsberg   firewire: Add cor...
920
921
  		return;
  	}
c781c06d1   Kristian Høgsberg   firewire: Clean u...
922
923
924
925
  	/*
  	 * FIXME: sanity check packet, is length correct, does tcodes
  	 * and addresses match.
  	 */
3038e353c   Kristian Høgsberg   firewire: Add cor...
926
927
928
  
  	switch (tcode) {
  	case TCODE_READ_QUADLET_RESPONSE:
2639a6fb2   Kristian Høgsberg   firewire: Use str...
929
  		data = (u32 *) &p->header[3];
3038e353c   Kristian Høgsberg   firewire: Add cor...
930
931
932
933
934
935
936
937
938
939
  		data_length = 4;
  		break;
  
  	case TCODE_WRITE_RESPONSE:
  		data = NULL;
  		data_length = 0;
  		break;
  
  	case TCODE_READ_BLOCK_RESPONSE:
  	case TCODE_LOCK_RESPONSE:
93c4cceb9   Kristian Høgsberg   firewire: Handle ...
940
  		data = p->payload;
a77754a75   Kristian Høgsberg   firewire: Upperca...
941
  		data_length = HEADER_GET_DATA_LENGTH(p->header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
942
943
944
945
946
947
948
949
  		break;
  
  	default:
  		/* Should never happen, this is just to shut up gcc. */
  		data = NULL;
  		data_length = 0;
  		break;
  	}
10a4c7355   Stefan Richter   firewire: fix pan...
950
951
952
953
954
  	/*
  	 * The response handler may be executed while the request handler
  	 * is still pending.  Cancel the request handler.
  	 */
  	card->driver->cancel_packet(card, &t->packet);
3038e353c   Kristian Høgsberg   firewire: Add cor...
955
956
  	t->callback(card, rcode, data, data_length, t->callback_data);
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
957
  EXPORT_SYMBOL(fw_core_handle_response);
ae57988f6   Stefan Richter   firewire: fw-core...
958
  static const struct fw_address_region topology_map_region =
cca609771   Jarod Wilson   firewire: replace...
959
960
  	{ .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP,
  	  .end   = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, };
473d28c73   Kristian Høgsberg   firewire: Impleme...
961

53dca5117   Stefan Richter   firewire: remove ...
962
963
  static void handle_topology_map(struct fw_card *card, struct fw_request *request,
  		int tcode, int destination, int source, int generation,
33e553fe2   Stefan Richter   firewire: remove ...
964
965
  		unsigned long long offset, void *payload, size_t length,
  		void *callback_data)
473d28c73   Kristian Høgsberg   firewire: Impleme...
966
  {
cb7c96da3   Stefan Richter   firewire: core: o...
967
  	int start;
473d28c73   Kristian Høgsberg   firewire: Impleme...
968
969
970
971
972
973
974
975
976
977
978
979
  
  	if (!TCODE_IS_READ_REQUEST(tcode)) {
  		fw_send_response(card, request, RCODE_TYPE_ERROR);
  		return;
  	}
  
  	if ((offset & 3) > 0 || (length & 3) > 0) {
  		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
  		return;
  	}
  
  	start = (offset - topology_map_region.start) / 4;
cb7c96da3   Stefan Richter   firewire: core: o...
980
  	memcpy(payload, &card->topology_map[start], length);
473d28c73   Kristian Høgsberg   firewire: Impleme...
981
982
983
984
985
  
  	fw_send_response(card, request, RCODE_COMPLETE);
  }
  
  static struct fw_address_handler topology_map = {
85cb9b686   Stefan Richter   firewire: core: f...
986
  	.length			= 0x400,
473d28c73   Kristian Høgsberg   firewire: Impleme...
987
988
  	.address_callback	= handle_topology_map,
  };
ae57988f6   Stefan Richter   firewire: fw-core...
989
  static const struct fw_address_region registers_region =
cca609771   Jarod Wilson   firewire: replace...
990
991
  	{ .start = CSR_REGISTER_BASE,
  	  .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM, };
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
992

8e4b50f94   Clemens Ladisch   firewire: core: a...
993
994
995
996
997
  static void update_split_timeout(struct fw_card *card)
  {
  	unsigned int cycles;
  
  	cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19);
4ec4a67aa   Stefan Richter   firewire: use cla...
998
999
  	/* minimum per IEEE 1394, maximum which doesn't overflow OHCI */
  	cycles = clamp(cycles, 800u, 3u * 8000u);
8e4b50f94   Clemens Ladisch   firewire: core: a...
1000
1001
1002
1003
  
  	card->split_timeout_cycles = cycles;
  	card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000);
  }
53dca5117   Stefan Richter   firewire: remove ...
1004
1005
  static void handle_registers(struct fw_card *card, struct fw_request *request,
  		int tcode, int destination, int source, int generation,
33e553fe2   Stefan Richter   firewire: remove ...
1006
1007
  		unsigned long long offset, void *payload, size_t length,
  		void *callback_data)
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1008
  {
15f0d833f   Jarod Wilson   firewire: use bit...
1009
  	int reg = offset & ~CSR_REGISTER_BASE;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1010
  	__be32 *data = payload;
e534fe16b   Stefan Richter   firewire: impleme...
1011
  	int rcode = RCODE_COMPLETE;
8e4b50f94   Clemens Ladisch   firewire: core: a...
1012
  	unsigned long flags;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1013
1014
  
  	switch (reg) {
b384cf188   Stefan Richter   firewire: core: c...
1015
1016
1017
1018
1019
1020
  	case CSR_PRIORITY_BUDGET:
  		if (!card->priority_budget_implemented) {
  			rcode = RCODE_ADDRESS_ERROR;
  			break;
  		}
  		/* else fall through */
3e07ec0ee   Clemens Ladisch   firewire: core: a...
1021

506f1a319   Clemens Ladisch   firewire: add CSR...
1022
  	case CSR_NODE_IDS:
65b2742ac   Stefan Richter   firewire: 'add CS...
1023
1024
1025
1026
  		/*
  		 * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8
  		 * and 9.6, but interoperable with IEEE 1394.1-2004 bridges
  		 */
b384cf188   Stefan Richter   firewire: core: c...
1027
1028
1029
1030
1031
1032
1033
  		/* fall through */
  
  	case CSR_STATE_CLEAR:
  	case CSR_STATE_SET:
  	case CSR_CYCLE_TIME:
  	case CSR_BUS_TIME:
  	case CSR_BUSY_TIMEOUT:
506f1a319   Clemens Ladisch   firewire: add CSR...
1034
  		if (tcode == TCODE_READ_QUADLET_REQUEST)
0fcff4e39   Stefan Richter   firewire: rename ...
1035
  			*data = cpu_to_be32(card->driver->read_csr(card, reg));
506f1a319   Clemens Ladisch   firewire: add CSR...
1036
  		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
0fcff4e39   Stefan Richter   firewire: rename ...
1037
  			card->driver->write_csr(card, reg, be32_to_cpu(*data));
506f1a319   Clemens Ladisch   firewire: add CSR...
1038
1039
1040
  		else
  			rcode = RCODE_TYPE_ERROR;
  		break;
446eba0d6   Clemens Ladisch   firewire: core: a...
1041
  	case CSR_RESET_START:
7e0e314f1   Clemens Ladisch   firewire: core: a...
1042
  		if (tcode == TCODE_WRITE_QUADLET_REQUEST)
0fcff4e39   Stefan Richter   firewire: rename ...
1043
1044
  			card->driver->write_csr(card, CSR_STATE_CLEAR,
  						CSR_STATE_BIT_ABDICATE);
7e0e314f1   Clemens Ladisch   firewire: core: a...
1045
  		else
446eba0d6   Clemens Ladisch   firewire: core: a...
1046
1047
  			rcode = RCODE_TYPE_ERROR;
  		break;
8e4b50f94   Clemens Ladisch   firewire: core: a...
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
  	case CSR_SPLIT_TIMEOUT_HI:
  		if (tcode == TCODE_READ_QUADLET_REQUEST) {
  			*data = cpu_to_be32(card->split_timeout_hi);
  		} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
  			spin_lock_irqsave(&card->lock, flags);
  			card->split_timeout_hi = be32_to_cpu(*data) & 7;
  			update_split_timeout(card);
  			spin_unlock_irqrestore(&card->lock, flags);
  		} else {
  			rcode = RCODE_TYPE_ERROR;
  		}
  		break;
  
  	case CSR_SPLIT_TIMEOUT_LO:
  		if (tcode == TCODE_READ_QUADLET_REQUEST) {
  			*data = cpu_to_be32(card->split_timeout_lo);
  		} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
  			spin_lock_irqsave(&card->lock, flags);
  			card->split_timeout_lo =
  					be32_to_cpu(*data) & 0xfff80000;
  			update_split_timeout(card);
  			spin_unlock_irqrestore(&card->lock, flags);
  		} else {
  			rcode = RCODE_TYPE_ERROR;
  		}
  		break;
3d1f46eb6   Clemens Ladisch   firewire: core: a...
1074
1075
1076
1077
1078
1079
1080
1081
  	case CSR_MAINT_UTILITY:
  		if (tcode == TCODE_READ_QUADLET_REQUEST)
  			*data = card->maint_utility_register;
  		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
  			card->maint_utility_register = *data;
  		else
  			rcode = RCODE_TYPE_ERROR;
  		break;
e534fe16b   Stefan Richter   firewire: impleme...
1082
1083
1084
1085
1086
1087
1088
1089
1090
  	case CSR_BROADCAST_CHANNEL:
  		if (tcode == TCODE_READ_QUADLET_REQUEST)
  			*data = cpu_to_be32(card->broadcast_channel);
  		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
  			card->broadcast_channel =
  			    (be32_to_cpu(*data) & BROADCAST_CHANNEL_VALID) |
  			    BROADCAST_CHANNEL_INITIAL;
  		else
  			rcode = RCODE_TYPE_ERROR;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1091
1092
1093
1094
1095
1096
  		break;
  
  	case CSR_BUS_MANAGER_ID:
  	case CSR_BANDWIDTH_AVAILABLE:
  	case CSR_CHANNELS_AVAILABLE_HI:
  	case CSR_CHANNELS_AVAILABLE_LO:
c781c06d1   Kristian Høgsberg   firewire: Clean u...
1097
1098
  		/*
  		 * FIXME: these are handled by the OHCI hardware and
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1099
1100
1101
  		 * the stack never sees these request. If we add
  		 * support for a new type of controller that doesn't
  		 * handle this in hardware we need to deal with these
c781c06d1   Kristian Høgsberg   firewire: Clean u...
1102
1103
  		 * transactions.
  		 */
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1104
1105
  		BUG();
  		break;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1106
  	default:
e534fe16b   Stefan Richter   firewire: impleme...
1107
  		rcode = RCODE_ADDRESS_ERROR;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1108
1109
  		break;
  	}
e534fe16b   Stefan Richter   firewire: impleme...
1110
1111
  
  	fw_send_response(card, request, rcode);
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1112
1113
1114
1115
1116
1117
  }
  
  static struct fw_address_handler registers = {
  	.length			= 0x400,
  	.address_callback	= handle_registers,
  };
3038e353c   Kristian Høgsberg   firewire: Add cor...
1118
1119
1120
  MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
  MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
  MODULE_LICENSE("GPL");
937f68796   Kristian Høgsberg   firewire: Let an ...
1121
  static const u32 vendor_textual_descriptor[] = {
3038e353c   Kristian Høgsberg   firewire: Add cor...
1122
  	/* textual descriptor leaf () */
937f68796   Kristian Høgsberg   firewire: Let an ...
1123
  	0x00060000,
3038e353c   Kristian Høgsberg   firewire: Add cor...
1124
1125
1126
1127
1128
  	0x00000000,
  	0x00000000,
  	0x4c696e75,		/* L i n u */
  	0x78204669,		/* x   F i */
  	0x72657769,		/* r e w i */
937f68796   Kristian Høgsberg   firewire: Let an ...
1129
  	0x72650000,		/* r e     */
3038e353c   Kristian Høgsberg   firewire: Add cor...
1130
  };
937f68796   Kristian Høgsberg   firewire: Let an ...
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
  static const u32 model_textual_descriptor[] = {
  	/* model descriptor leaf () */
  	0x00030000,
  	0x00000000,
  	0x00000000,
  	0x4a756a75,		/* J u j u */
  };
  
  static struct fw_descriptor vendor_id_descriptor = {
  	.length = ARRAY_SIZE(vendor_textual_descriptor),
  	.immediate = 0x03d00d1e,
3038e353c   Kristian Høgsberg   firewire: Add cor...
1142
  	.key = 0x81000000,
937f68796   Kristian Høgsberg   firewire: Let an ...
1143
1144
1145
1146
1147
1148
1149
1150
  	.data = vendor_textual_descriptor,
  };
  
  static struct fw_descriptor model_id_descriptor = {
  	.length = ARRAY_SIZE(model_textual_descriptor),
  	.immediate = 0x17000001,
  	.key = 0x81000000,
  	.data = model_textual_descriptor,
3038e353c   Kristian Høgsberg   firewire: Add cor...
1151
  };
3038e353c   Kristian Høgsberg   firewire: Add cor...
1152
1153
  static int __init fw_core_init(void)
  {
2dbd7d7e2   Stefan Richter   firewire: standar...
1154
  	int ret;
3038e353c   Kristian Høgsberg   firewire: Add cor...
1155

105e53f86   Stefan Richter   firewire: sbp2: p...
1156
1157
1158
  	fw_workqueue = alloc_workqueue("firewire",
  				       WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
  	if (!fw_workqueue)
6ea9e7bbf   Stefan Richter   firewire: core: u...
1159
  		return -ENOMEM;
2dbd7d7e2   Stefan Richter   firewire: standar...
1160
  	ret = bus_register(&fw_bus_type);
6ea9e7bbf   Stefan Richter   firewire: core: u...
1161
  	if (ret < 0) {
105e53f86   Stefan Richter   firewire: sbp2: p...
1162
  		destroy_workqueue(fw_workqueue);
2dbd7d7e2   Stefan Richter   firewire: standar...
1163
  		return ret;
6ea9e7bbf   Stefan Richter   firewire: core: u...
1164
  	}
3038e353c   Kristian Høgsberg   firewire: Add cor...
1165

a3aca3dab   Kristian Høgsberg   firewire: Switch ...
1166
1167
1168
  	fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
  	if (fw_cdev_major < 0) {
  		bus_unregister(&fw_bus_type);
105e53f86   Stefan Richter   firewire: sbp2: p...
1169
  		destroy_workqueue(fw_workqueue);
a3aca3dab   Kristian Høgsberg   firewire: Switch ...
1170
1171
  		return fw_cdev_major;
  	}
c490a6dec   Stefan Richter   firewire: core: r...
1172
1173
1174
1175
  	fw_core_add_address_handler(&topology_map, &topology_map_region);
  	fw_core_add_address_handler(&registers, &registers_region);
  	fw_core_add_descriptor(&vendor_id_descriptor);
  	fw_core_add_descriptor(&model_id_descriptor);
3038e353c   Kristian Høgsberg   firewire: Add cor...
1176
1177
1178
1179
1180
1181
  
  	return 0;
  }
  
  static void __exit fw_core_cleanup(void)
  {
a3aca3dab   Kristian Høgsberg   firewire: Switch ...
1182
  	unregister_chrdev(fw_cdev_major, "firewire");
3038e353c   Kristian Høgsberg   firewire: Add cor...
1183
  	bus_unregister(&fw_bus_type);
105e53f86   Stefan Richter   firewire: sbp2: p...
1184
  	destroy_workqueue(fw_workqueue);
d6053e08f   Stefan Richter   firewire: fix sma...
1185
  	idr_destroy(&fw_device_idr);
3038e353c   Kristian Høgsberg   firewire: Add cor...
1186
1187
1188
1189
  }
  
  module_init(fw_core_init);
  module_exit(fw_core_cleanup);