Blame view

drivers/ieee1394/csr1212.c 37.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  /*
   * csr1212.c -- IEEE 1212 Control and Status Register support for Linux
   *
   * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
   *                    Steve Kinneberg <kinnebergsteve@acmsystems.com>
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   *    1. Redistributions of source code must retain the above copyright notice,
   *       this list of conditions and the following disclaimer.
   *    2. Redistributions in binary form must reproduce the above copyright
   *       notice, this list of conditions and the following disclaimer in the
   *       documentation and/or other materials provided with the distribution.
   *    3. The name of the author may not be used to endorse or promote products
   *       derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
   * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  
  /* TODO List:
   * - Verify interface consistency: i.e., public functions that take a size
   *   parameter expect size to be in bytes.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
   */
7fb9addba   Stefan Richter   ieee1394: drop cs...
35
  #include <linux/errno.h>
d26525034   Stefan Richter   ieee1394: csr1212...
36
  #include <linux/kernel.h>
96c25c81e   Vegard Nossum   ieee1394/csr1212:...
37
  #include <linux/kmemcheck.h>
7fb9addba   Stefan Richter   ieee1394: drop cs...
38
  #include <linux/string.h>
64ff71232   Stefan Richter   ieee1394: stricte...
39
  #include <asm/bug.h>
7fb9addba   Stefan Richter   ieee1394: drop cs...
40
  #include <asm/byteorder.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
47
48
49
  
  #include "csr1212.h"
  
  
  /* Permitted key type for each key id */
  #define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
  #define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
  #define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
  #define __L (1 << CSR1212_KV_TYPE_LEAF)
982610bd0   Stefan Richter   ieee1394: csr1212...
50
  static const u8 csr1212_key_id_type_map[0x30] = {
0749aaab4   Andrea Guzzo   ieee1394: modifie...
51
  	__C,			/* used by Apple iSight */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
  	__D | __L,		/* Descriptor */
  	__I | __D | __L,	/* Bus_Dependent_Info */
  	__I | __D | __L,	/* Vendor */
  	__I,			/* Hardware_Version */
  	0, 0,			/* Reserved */
0749aaab4   Andrea Guzzo   ieee1394: modifie...
57
58
  	__D | __L | __I,	/* Module */
  	__I, 0, 0, 0,		/* used by Apple iSight, Reserved */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  	__I,			/* Node_Capabilities */
  	__L,			/* EUI_64 */
  	0, 0, 0,		/* Reserved */
  	__D,			/* Unit */
  	__I,			/* Specifier_ID */
  	__I,			/* Version */
  	__I | __C | __D | __L,	/* Dependent_Info */
  	__L,			/* Unit_Location */
  	0,			/* Reserved */
  	__I,			/* Model */
  	__D,			/* Instance */
  	__L,			/* Keyword */
  	__D,			/* Feature */
  	__L,			/* Extended_ROM */
  	__I,			/* Extended_Key_Specifier_ID */
  	__I,			/* Extended_Key */
  	__I | __C | __D | __L,	/* Extended_Data */
  	__L,			/* Modifiable_Descriptor */
  	__I,			/* Directory_ID */
  	__I,			/* Revision */
  };
  #undef __I
  #undef __C
  #undef __D
  #undef __L
982610bd0   Stefan Richter   ieee1394: csr1212...
84
  #define quads_to_bytes(_q) ((_q) * sizeof(u32))
68e2aa793   Julia Lawall   ieee1394: Use DIV...
85
  #define bytes_to_quads(_b) DIV_ROUND_UP(_b, sizeof(u32))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

6c88e4756   Stefan Richter   ieee1394: remove ...
87
  static void free_keyval(struct csr1212_keyval *kv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
93
94
  {
  	if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
  	    (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
  		CSR1212_FREE(kv->value.leaf.data);
  
  	CSR1212_FREE(kv);
  }
982610bd0   Stefan Richter   ieee1394: csr1212...
95
  static u16 csr1212_crc16(const u32 *buffer, size_t length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
  {
  	int shift;
982610bd0   Stefan Richter   ieee1394: csr1212...
98
99
  	u32 data;
  	u16 sum, crc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
  
  	for (; length; length--) {
7fb9addba   Stefan Richter   ieee1394: drop cs...
102
  		data = be32_to_cpu(*buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
  		buffer++;
  		for (shift = 28; shift >= 0; shift -= 4 ) {
  			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
  			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
  		}
  		crc &= 0xffff;
  	}
7fb9addba   Stefan Richter   ieee1394: drop cs...
110
  	return cpu_to_be16(crc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  }
d26525034   Stefan Richter   ieee1394: csr1212...
112
  /* Microsoft computes the CRC with the bytes in reverse order. */
982610bd0   Stefan Richter   ieee1394: csr1212...
113
  static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  {
  	int shift;
982610bd0   Stefan Richter   ieee1394: csr1212...
116
117
  	u32 data;
  	u16 sum, crc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
  
  	for (; length; length--) {
7fb9addba   Stefan Richter   ieee1394: drop cs...
120
  		data = le32_to_cpu(*buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
  		buffer++;
  		for (shift = 28; shift >= 0; shift -= 4 ) {
  			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
  			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
  		}
  		crc &= 0xffff;
  	}
7fb9addba   Stefan Richter   ieee1394: drop cs...
128
  	return cpu_to_be16(crc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130

6c88e4756   Stefan Richter   ieee1394: remove ...
131
132
  static struct csr1212_dentry *
  csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
  {
  	struct csr1212_dentry *pos;
  
  	for (pos = dir->value.directory.dentries_head;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
137
  	     pos != NULL; pos = pos->next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
  		if (pos->kv == kv)
  			return pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  	return NULL;
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
142
  static struct csr1212_keyval *
982610bd0   Stefan Richter   ieee1394: csr1212...
143
  csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
  {
  	struct csr1212_keyval *kv;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
146
  	for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
  		if (kv->offset == offset)
  			return kv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
  	return NULL;
  }
  
  
  /* Creation Routines */
6c88e4756   Stefan Richter   ieee1394: remove ...
154

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
  				       size_t bus_info_size, void *private)
  {
  	struct csr1212_csr *csr;
  
  	csr = CSR1212_MALLOC(sizeof(*csr));
  	if (!csr)
  		return NULL;
  
  	csr->cache_head =
  		csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
  					 CSR1212_CONFIG_ROM_SPACE_SIZE);
  	if (!csr->cache_head) {
  		CSR1212_FREE(csr);
  		return NULL;
  	}
  
  	/* The keyval key id is not used for the root node, but a valid key id
  	 * that can be used for a directory needs to be passed to
  	 * csr1212_new_directory(). */
  	csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
  	if (!csr->root_kv) {
  		CSR1212_FREE(csr->cache_head);
  		CSR1212_FREE(csr);
  		return NULL;
  	}
  
  	csr->bus_info_data = csr->cache_head->data;
  	csr->bus_info_len = bus_info_size;
  	csr->crc_len = bus_info_size;
  	csr->ops = ops;
  	csr->private = private;
  	csr->cache_tail = csr->cache_head;
  
  	return csr;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  void csr1212_init_local_csr(struct csr1212_csr *csr,
982610bd0   Stefan Richter   ieee1394: csr1212...
192
  			    const u32 *bus_info_data, int max_rom)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  {
  	static const int mr_map[] = { 4, 64, 1024, 0 };
1934b8b65   Ben Collins   [PATCH] Sync up i...
195
  	BUG_ON(max_rom & ~0x3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
  	csr->max_rom = mr_map[max_rom];
  	memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
  }
982610bd0   Stefan Richter   ieee1394: csr1212...
199
  static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
206
207
208
  {
  	struct csr1212_keyval *kv;
  
  	if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
  		return NULL;
  
  	kv = CSR1212_MALLOC(sizeof(*kv));
  	if (!kv)
  		return NULL;
17a19b795   Stefan Richter   ieee1394: csr1212...
209
  	atomic_set(&kv->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
  	kv->key.type = type;
  	kv->key.id = key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  	kv->associate = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
  	kv->next = NULL;
  	kv->prev = NULL;
  	kv->offset = 0;
  	kv->valid = 0;
  	return kv;
  }
982610bd0   Stefan Richter   ieee1394: csr1212...
219
  struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
221
  	struct csr1212_keyval *kv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222

c868ae2a1   Stefan Richter   ieee1394: csr1212...
223
  	kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
226
227
228
229
230
  	if (!kv)
  		return NULL;
  
  	kv->value.immediate = value;
  	kv->valid = 1;
  	return kv;
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
231
  static struct csr1212_keyval *
982610bd0   Stefan Richter   ieee1394: csr1212...
232
  csr1212_new_leaf(u8 key, const void *data, size_t data_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
234
  	struct csr1212_keyval *kv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235

c868ae2a1   Stefan Richter   ieee1394: csr1212...
236
  	kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  	if (!kv)
  		return NULL;
  
  	if (data_len > 0) {
  		kv->value.leaf.data = CSR1212_MALLOC(data_len);
  		if (!kv->value.leaf.data) {
  			CSR1212_FREE(kv);
  			return NULL;
  		}
  
  		if (data)
  			memcpy(kv->value.leaf.data, data, data_len);
  	} else {
  		kv->value.leaf.data = NULL;
  	}
  
  	kv->value.leaf.len = bytes_to_quads(data_len);
  	kv->offset = 0;
  	kv->valid = 1;
  
  	return kv;
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
259
  static struct csr1212_keyval *
982610bd0   Stefan Richter   ieee1394: csr1212...
260
  csr1212_new_csr_offset(u8 key, u32 csr_offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
262
  	struct csr1212_keyval *kv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263

c868ae2a1   Stefan Richter   ieee1394: csr1212...
264
  	kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
270
271
272
273
  	if (!kv)
  		return NULL;
  
  	kv->value.csr_offset = csr_offset;
  
  	kv->offset = 0;
  	kv->valid = 1;
  	return kv;
  }
982610bd0   Stefan Richter   ieee1394: csr1212...
274
  struct csr1212_keyval *csr1212_new_directory(u8 key)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
  {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
276
  	struct csr1212_keyval *kv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277

c868ae2a1   Stefan Richter   ieee1394: csr1212...
278
  	kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
284
285
286
287
288
  	if (!kv)
  		return NULL;
  
  	kv->value.directory.len = 0;
  	kv->offset = 0;
  	kv->value.directory.dentries_head = NULL;
  	kv->value.directory.dentries_tail = NULL;
  	kv->valid = 1;
  	return kv;
  }
64ff71232   Stefan Richter   ieee1394: stricte...
289
290
  void csr1212_associate_keyval(struct csr1212_keyval *kv,
  			      struct csr1212_keyval *associate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  {
64ff71232   Stefan Richter   ieee1394: stricte...
292
293
294
295
296
297
298
  	BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
  	       (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
  		associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
  		associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
  		associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
  		associate->key.id < 0x30) ||
  	       (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
c868ae2a1   Stefan Richter   ieee1394: csr1212...
299
  		associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
64ff71232   Stefan Richter   ieee1394: stricte...
300
301
302
303
304
305
  	       (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
  		associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
  	       (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
  		kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
  	       (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
  		kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
  
  	if (kv->associate)
  		csr1212_release_keyval(kv->associate);
17a19b795   Stefan Richter   ieee1394: csr1212...
309
  	csr1212_keep_keyval(associate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  	kv->associate = associate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  }
17a19b795   Stefan Richter   ieee1394: csr1212...
312
313
314
  static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
  						struct csr1212_keyval *kv,
  						bool keep_keyval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  {
  	struct csr1212_dentry *dentry;
64ff71232   Stefan Richter   ieee1394: stricte...
317
  	BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
  
  	dentry = CSR1212_MALLOC(sizeof(*dentry));
  	if (!dentry)
7fb9addba   Stefan Richter   ieee1394: drop cs...
321
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322

17a19b795   Stefan Richter   ieee1394: csr1212...
323
324
  	if (keep_keyval)
  		csr1212_keep_keyval(kv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  	dentry->kv = kv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
333
334
335
336
337
  	dentry->next = NULL;
  	dentry->prev = dir->value.directory.dentries_tail;
  
  	if (!dir->value.directory.dentries_head)
  		dir->value.directory.dentries_head = dentry;
  
  	if (dir->value.directory.dentries_tail)
  		dir->value.directory.dentries_tail->next = dentry;
  	dir->value.directory.dentries_tail = dentry;
  
  	return CSR1212_SUCCESS;
  }
17a19b795   Stefan Richter   ieee1394: csr1212...
338
339
340
341
342
  int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
  				       struct csr1212_keyval *kv)
  {
  	return __csr1212_attach_keyval_to_directory(dir, kv, true);
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
343
344
345
346
347
  #define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
  	(&((kv)->value.leaf.data[1]))
  
  #define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
  	((kv)->value.leaf.data[0] = \
7fb9addba   Stefan Richter   ieee1394: drop cs...
348
349
  	 cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
  		     ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
6c88e4756   Stefan Richter   ieee1394: remove ...
350
351
  #define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
  	((kv)->value.leaf.data[0] = \
7fb9addba   Stefan Richter   ieee1394: drop cs...
352
353
354
  	 cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
  		      CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
  		     ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
6c88e4756   Stefan Richter   ieee1394: remove ...
355
356
  
  static struct csr1212_keyval *
982610bd0   Stefan Richter   ieee1394: csr1212...
357
  csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
6c88e4756   Stefan Richter   ieee1394: remove ...
358
  			    const void *data, size_t data_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
364
365
  {
  	struct csr1212_keyval *kv;
  
  	kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
  			      data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
  	if (!kv)
  		return NULL;
96c25c81e   Vegard Nossum   ieee1394/csr1212:...
366
  	kmemcheck_annotate_variable(kv->value.leaf.data[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
  	CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
  	CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
a1c6250cb   Stefan Richter   ieee1394: shrink ...
369
  	if (data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  		memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
  
  	return kv;
  }
a1c6250cb   Stefan Richter   ieee1394: shrink ...
374
  /* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
  static int csr1212_check_minimal_ascii(const char *s)
  {
  	static const char minimal_ascii_table[] = {
a1c6250cb   Stefan Richter   ieee1394: shrink ...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  					/*  1   2   4   8  16  32  64  128 */
  		128,			/* --, --, --, --, --, --, --, 07, */
  		4 + 16 + 32,		/* --, --, 0a, --, 0C, 0D, --, --, */
  		0,			/* --, --, --, --, --, --, --, --, */
  		0,			/* --, --, --, --, --, --, --, --, */
  		255 - 8 - 16,		/* 20, 21, 22, --, --, 25, 26, 27, */
  		255,			/* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */
  		255,			/* 30, 31, 32, 33, 34, 35, 36, 37, */
  		255,			/* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */
  		255,			/* 40, 41, 42, 43, 44, 45, 46, 47, */
  		255,			/* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */
  		255,			/* 50, 51, 52, 53, 54, 55, 56, 57, */
  		1 + 2 + 4 + 128,	/* 58, 59, 5a, --, --, --, --, 5f, */
  		255 - 1,		/* --, 61, 62, 63, 64, 65, 66, 67, */
  		255,			/* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */
  		255,			/* 70, 71, 72, 73, 74, 75, 76, 77, */
  		1 + 2 + 4,		/* 78, 79, 7a, --, --, --, --, --, */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
  	};
a1c6250cb   Stefan Richter   ieee1394: shrink ...
396
  	int i, j;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  	for (; *s; s++) {
a1c6250cb   Stefan Richter   ieee1394: shrink ...
398
399
400
401
402
403
  		i = *s >> 3;		/*  i = *s / 8;		*/
  		j = 1 << (*s & 3);	/*  j = 1 << (*s % 8);	*/
  
  		if (i >= ARRAY_SIZE(minimal_ascii_table) ||
  		    !(minimal_ascii_table[i] & j))
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  	return 0;
  }
a1c6250cb   Stefan Richter   ieee1394: shrink ...
407
  /* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
  struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
  {
a1c6250cb   Stefan Richter   ieee1394: shrink ...
410
411
412
413
414
415
416
417
418
419
420
421
  	struct csr1212_keyval *kv;
  	u32 *text;
  	size_t str_len, quads;
  
  	if (!s || !*s || csr1212_check_minimal_ascii(s))
  		return NULL;
  
  	str_len = strlen(s);
  	quads = bytes_to_quads(str_len);
  	kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) +
  				      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
  	if (!kv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  		return NULL;
a1c6250cb   Stefan Richter   ieee1394: shrink ...
423
424
425
426
427
428
  	kv->value.leaf.data[1] = 0;	/* width, character_set, language */
  	text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
  	text[quads - 1] = 0;		/* padding */
  	memcpy(text, s, str_len);
  
  	return kv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  
  /* Destruction Routines */
  
  void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
  					  struct csr1212_keyval *kv)
  {
  	struct csr1212_dentry *dentry;
  
  	if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
  		return;
  
  	dentry = csr1212_find_keyval(dir, kv);
  
  	if (!dentry)
  		return;
  
  	if (dentry->prev)
  		dentry->prev->next = dentry->next;
  	if (dentry->next)
  		dentry->next->prev = dentry->prev;
  	if (dir->value.directory.dentries_head == dentry)
  		dir->value.directory.dentries_head = dentry->next;
  	if (dir->value.directory.dentries_tail == dentry)
  		dir->value.directory.dentries_tail = dentry->prev;
  
  	CSR1212_FREE(dentry);
  
  	csr1212_release_keyval(kv);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
  /* This function is used to free the memory taken by a keyval.  If the given
   * keyval is a directory type, then any keyvals contained in that directory
17a19b795   Stefan Richter   ieee1394: csr1212...
461
   * will be destroyed as well if noone holds a reference on them.  By means of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
   * list manipulation, this routine will descend a directory structure in a
   * non-recursive manner. */
17a19b795   Stefan Richter   ieee1394: csr1212...
464
  void csr1212_release_keyval(struct csr1212_keyval *kv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
  {
  	struct csr1212_keyval *k, *a;
  	struct csr1212_dentry dentry;
  	struct csr1212_dentry *head, *tail;
17a19b795   Stefan Richter   ieee1394: csr1212...
469
470
  	if (!atomic_dec_and_test(&kv->refcnt))
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
476
477
478
479
480
481
  	dentry.kv = kv;
  	dentry.next = NULL;
  	dentry.prev = NULL;
  
  	head = &dentry;
  	tail = head;
  
  	while (head) {
  		k = head->kv;
  
  		while (k) {
17a19b795   Stefan Richter   ieee1394: csr1212...
482
483
  			/* must not dec_and_test kv->refcnt again */
  			if (k != kv && !atomic_dec_and_test(&k->refcnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
488
  				break;
  
  			a = k->associate;
  
  			if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
489
  				/* If the current entry is a directory, move all
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
  				 * the entries to the destruction list. */
  				if (k->value.directory.dentries_head) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
492
493
494
495
  					tail->next =
  					    k->value.directory.dentries_head;
  					k->value.directory.dentries_head->prev =
  					    tail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
499
500
501
502
503
504
  					tail = k->value.directory.dentries_tail;
  				}
  			}
  			free_keyval(k);
  			k = a;
  		}
  
  		head = head->next;
  		if (head) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
505
  			if (head->prev && head->prev != &dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  				CSR1212_FREE(head->prev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  			head->prev = NULL;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
508
  		} else if (tail != &dentry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  			CSR1212_FREE(tail);
c868ae2a1   Stefan Richter   ieee1394: csr1212...
510
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
  void csr1212_destroy_csr(struct csr1212_csr *csr)
  {
  	struct csr1212_csr_rom_cache *c, *oc;
  	struct csr1212_cache_region *cr, *ocr;
  
  	csr1212_release_keyval(csr->root_kv);
  
  	c = csr->cache_head;
  	while (c) {
  		oc = c;
  		cr = c->filled_head;
  		while (cr) {
  			ocr = cr;
  			cr = cr->next;
  			CSR1212_FREE(ocr);
  		}
  		c = c->next;
  		CSR1212_FREE(oc);
  	}
  
  	CSR1212_FREE(csr);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
  /* CSR Image Creation */
  
  static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
  {
  	struct csr1212_csr_rom_cache *cache;
982610bd0   Stefan Richter   ieee1394: csr1212...
540
  	u64 csr_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541

64ff71232   Stefan Richter   ieee1394: stricte...
542
543
  	BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
  	       !csr->ops->release_addr || csr->max_rom < 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
  
  	/* ROM size must be a multiple of csr->max_rom */
  	romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
c868ae2a1   Stefan Richter   ieee1394: csr1212...
547
548
549
  	csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
  						 csr->private);
  	if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
7fb9addba   Stefan Richter   ieee1394: drop cs...
550
  		return -ENOMEM;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
551

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
  	if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
  		/* Invalid address returned from allocate_addr_range(). */
  		csr->ops->release_addr(csr_addr, csr->private);
7fb9addba   Stefan Richter   ieee1394: drop cs...
555
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  	}
c868ae2a1   Stefan Richter   ieee1394: csr1212...
557
558
  	cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
  					 romsize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
  	if (!cache) {
  		csr->ops->release_addr(csr_addr, csr->private);
7fb9addba   Stefan Richter   ieee1394: drop cs...
561
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
  	}
c868ae2a1   Stefan Richter   ieee1394: csr1212...
563
564
  	cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
  					    CSR1212_KV_ID_EXTENDED_ROM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
  	if (!cache->ext_rom) {
  		csr->ops->release_addr(csr_addr, csr->private);
  		CSR1212_FREE(cache);
7fb9addba   Stefan Richter   ieee1394: drop cs...
568
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
  	}
c868ae2a1   Stefan Richter   ieee1394: csr1212...
570
571
  	if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
  	    CSR1212_SUCCESS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
574
  		csr1212_release_keyval(cache->ext_rom);
  		csr->ops->release_addr(csr_addr, csr->private);
  		CSR1212_FREE(cache);
7fb9addba   Stefan Richter   ieee1394: drop cs...
575
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
578
579
580
581
582
583
584
585
586
  	}
  	cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
  	cache->ext_rom->value.leaf.len = -1;
  	cache->ext_rom->value.leaf.data = cache->data;
  
  	/* Add cache to tail of cache list */
  	cache->prev = csr->cache_tail;
  	csr->cache_tail->next = cache;
  	csr->cache_tail = cache;
  	return CSR1212_SUCCESS;
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
587
588
  static void csr1212_remove_cache(struct csr1212_csr *csr,
  				 struct csr1212_csr_rom_cache *cache)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
595
596
597
598
599
600
  {
  	if (csr->cache_head == cache)
  		csr->cache_head = cache->next;
  	if (csr->cache_tail == cache)
  		csr->cache_tail = cache->prev;
  
  	if (cache->prev)
  		cache->prev->next = cache->next;
  	if (cache->next)
  		cache->next->prev = cache->prev;
  
  	if (cache->ext_rom) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
601
602
  		csr1212_detach_keyval_from_directory(csr->root_kv,
  						     cache->ext_rom);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
  		csr1212_release_keyval(cache->ext_rom);
  	}
  
  	CSR1212_FREE(cache);
  }
  
  static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
  					  struct csr1212_keyval **layout_tail)
  {
  	struct csr1212_dentry *dentry;
  	struct csr1212_keyval *dkv;
  	struct csr1212_keyval *last_extkey_spec = NULL;
  	struct csr1212_keyval *last_extkey = NULL;
  	int num_entries = 0;
  
  	for (dentry = dir->value.directory.dentries_head; dentry;
  	     dentry = dentry->next) {
  		for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
  			/* Special Case: Extended Key Specifier_ID */
c868ae2a1   Stefan Richter   ieee1394: csr1212...
622
623
624
  			if (dkv->key.id ==
  			    CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
  				if (last_extkey_spec == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  					last_extkey_spec = dkv;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
626
627
  				else if (dkv->value.immediate !=
  					 last_extkey_spec->value.immediate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  					last_extkey_spec = dkv;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
629
  				else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  					continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
  			/* Special Case: Extended Key */
  			} else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
633
  				if (last_extkey == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
  					last_extkey = dkv;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
635
636
  				else if (dkv->value.immediate !=
  					 last_extkey->value.immediate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
  					last_extkey = dkv;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
638
  				else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  					continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
  			}
  
  			num_entries += 1;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
643
  			switch (dkv->key.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  			default:
  			case CSR1212_KV_TYPE_IMMEDIATE:
  			case CSR1212_KV_TYPE_CSR_OFFSET:
  				break;
  			case CSR1212_KV_TYPE_LEAF:
  			case CSR1212_KV_TYPE_DIRECTORY:
  				/* Remove from list */
  				if (dkv->prev && (dkv->prev->next == dkv))
  					dkv->prev->next = dkv->next;
  				if (dkv->next && (dkv->next->prev == dkv))
  					dkv->next->prev = dkv->prev;
  				//if (dkv == *layout_tail)
  				//	*layout_tail = dkv->prev;
  
  				/* Special case: Extended ROM leafs */
  				if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
  					dkv->value.leaf.len = -1;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
661
662
663
  					/* Don't add Extended ROM leafs in the
  					 * layout list, they are handled
  					 * differently. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  					break;
  				}
  
  				/* Add to tail of list */
  				dkv->next = NULL;
  				dkv->prev = *layout_tail;
  				(*layout_tail)->next = dkv;
  				*layout_tail = dkv;
  				break;
  			}
  		}
  	}
  	return num_entries;
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
678
  static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
  {
  	struct csr1212_keyval *ltail = kv;
  	size_t agg_size = 0;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
682
683
  	while (kv) {
  		switch (kv->key.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
687
688
689
  		case CSR1212_KV_TYPE_LEAF:
  			/* Add 1 quadlet for crc/len field */
  			agg_size += kv->value.leaf.len + 1;
  			break;
  
  		case CSR1212_KV_TYPE_DIRECTORY:
c868ae2a1   Stefan Richter   ieee1394: csr1212...
690
691
  			kv->value.directory.len =
  				csr1212_generate_layout_subdir(kv, &ltail);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
696
697
698
699
  			/* Add 1 quadlet for crc/len field */
  			agg_size += kv->value.directory.len + 1;
  			break;
  		}
  		kv = kv->next;
  	}
  	return quads_to_bytes(agg_size);
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
700
701
702
  static struct csr1212_keyval *
  csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
  			   struct csr1212_keyval *start_kv, int start_pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
706
707
708
709
  {
  	struct csr1212_keyval *kv = start_kv;
  	struct csr1212_keyval *okv = start_kv;
  	int pos = start_pos;
  	int kv_len = 0, okv_len = 0;
  
  	cache->layout_head = kv;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
710
  	while (kv && pos < cache->size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  		/* Special case: Extended ROM leafs */
c868ae2a1   Stefan Richter   ieee1394: csr1212...
712
  		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  			kv->offset = cache->offset + pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714

c868ae2a1   Stefan Richter   ieee1394: csr1212...
715
  		switch (kv->key.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
720
721
722
723
724
725
  		case CSR1212_KV_TYPE_LEAF:
  			kv_len = kv->value.leaf.len;
  			break;
  
  		case CSR1212_KV_TYPE_DIRECTORY:
  			kv_len = kv->value.directory.len;
  			break;
  
  		default:
  			/* Should never get here */
c94ccf9e3   Stefan Richter   ieee1394: csr1212...
726
  			WARN_ON(1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
731
732
733
734
735
736
737
738
739
  			break;
  		}
  
  		pos += quads_to_bytes(kv_len + 1);
  
  		if (pos <= cache->size) {
  			okv = kv;
  			okv_len = kv_len;
  			kv = kv->next;
  		}
  	}
  
  	cache->layout_tail = okv;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
740
  	cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
  
  	return kv;
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
744
745
746
747
748
749
  #define CSR1212_KV_KEY_SHIFT		24
  #define CSR1212_KV_KEY_TYPE_SHIFT	6
  #define CSR1212_KV_KEY_ID_MASK		0x3f
  #define CSR1212_KV_KEY_TYPE_MASK	0x3	/* after shift */
  
  static void
982610bd0   Stefan Richter   ieee1394: csr1212...
750
  csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
755
  {
  	struct csr1212_dentry *dentry;
  	struct csr1212_keyval *last_extkey_spec = NULL;
  	struct csr1212_keyval *last_extkey = NULL;
  	int index = 0;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
756
757
758
  	for (dentry = dir->value.directory.dentries_head;
  	     dentry;
  	     dentry = dentry->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
  		struct csr1212_keyval *a;
  
  		for (a = dentry->kv; a; a = a->associate) {
982610bd0   Stefan Richter   ieee1394: csr1212...
762
  			u32 value = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
  
  			/* Special Case: Extended Key Specifier_ID */
c868ae2a1   Stefan Richter   ieee1394: csr1212...
765
766
767
  			if (a->key.id ==
  			    CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
  				if (last_extkey_spec == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  					last_extkey_spec = a;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
769
770
  				else if (a->value.immediate !=
  					 last_extkey_spec->value.immediate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  					last_extkey_spec = a;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
772
  				else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  					continue;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
774

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
  			/* Special Case: Extended Key */
  			} else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
777
  				if (last_extkey == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
  					last_extkey = a;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
779
780
  				else if (a->value.immediate !=
  					 last_extkey->value.immediate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  					last_extkey = a;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
782
  				else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  					continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  			}
c868ae2a1   Stefan Richter   ieee1394: csr1212...
785
  			switch (a->key.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  			case CSR1212_KV_TYPE_IMMEDIATE:
  				value = a->value.immediate;
  				break;
  			case CSR1212_KV_TYPE_CSR_OFFSET:
  				value = a->value.csr_offset;
  				break;
  			case CSR1212_KV_TYPE_LEAF:
  				value = a->offset;
  				value -= dir->offset + quads_to_bytes(1+index);
  				value = bytes_to_quads(value);
  				break;
  			case CSR1212_KV_TYPE_DIRECTORY:
  				value = a->offset;
  				value -= dir->offset + quads_to_bytes(1+index);
  				value = bytes_to_quads(value);
  				break;
  			default:
  				/* Should never get here */
c94ccf9e3   Stefan Richter   ieee1394: csr1212...
804
805
  				WARN_ON(1);
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
  			}
c868ae2a1   Stefan Richter   ieee1394: csr1212...
807
808
  			value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
  				 CSR1212_KV_KEY_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  			value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
c868ae2a1   Stefan Richter   ieee1394: csr1212...
810
811
  				 (CSR1212_KV_KEY_SHIFT +
  				  CSR1212_KV_KEY_TYPE_SHIFT);
7fb9addba   Stefan Richter   ieee1394: drop cs...
812
  			data_buffer[index] = cpu_to_be32(value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
815
816
  			index++;
  		}
  	}
  }
6c88e4756   Stefan Richter   ieee1394: remove ...
817
  struct csr1212_keyval_img {
982610bd0   Stefan Richter   ieee1394: csr1212...
818
819
  	u16 length;
  	u16 crc;
6c88e4756   Stefan Richter   ieee1394: remove ...
820
821
  
  	/* Must be last */
982610bd0   Stefan Richter   ieee1394: csr1212...
822
  	u32 data[0];	/* older gcc can't handle [] which is standard */
6c88e4756   Stefan Richter   ieee1394: remove ...
823
824
825
  };
  
  static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
828
  {
  	struct csr1212_keyval *kv, *nkv;
  	struct csr1212_keyval_img *kvi;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
829
830
831
832
833
834
  	for (kv = cache->layout_head;
  	     kv != cache->layout_tail->next;
  	     kv = nkv) {
  		kvi = (struct csr1212_keyval_img *)(cache->data +
  				bytes_to_quads(kv->offset - cache->offset));
  		switch (kv->key.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
  		default:
  		case CSR1212_KV_TYPE_IMMEDIATE:
  		case CSR1212_KV_TYPE_CSR_OFFSET:
  			/* Should never get here */
c94ccf9e3   Stefan Richter   ieee1394: csr1212...
839
840
  			WARN_ON(1);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
843
844
845
846
847
  
  		case CSR1212_KV_TYPE_LEAF:
  			/* Don't copy over Extended ROM areas, they are
  			 * already filled out! */
  			if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
  				memcpy(kvi->data, kv->value.leaf.data,
  				       quads_to_bytes(kv->value.leaf.len));
7fb9addba   Stefan Richter   ieee1394: drop cs...
848
  			kvi->length = cpu_to_be16(kv->value.leaf.len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
850
851
852
853
  			kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
  			break;
  
  		case CSR1212_KV_TYPE_DIRECTORY:
  			csr1212_generate_tree_subdir(kv, kvi->data);
7fb9addba   Stefan Richter   ieee1394: drop cs...
854
  			kvi->length = cpu_to_be16(kv->value.directory.len);
c868ae2a1   Stefan Richter   ieee1394: csr1212...
855
856
  			kvi->crc = csr1212_crc16(kvi->data,
  						 kv->value.directory.len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
858
859
860
861
862
863
864
865
866
867
868
  			break;
  		}
  
  		nkv = kv->next;
  		if (kv->prev)
  			kv->prev->next = NULL;
  		if (kv->next)
  			kv->next->prev = NULL;
  		kv->prev = NULL;
  		kv->next = NULL;
  	}
  }
fd2f3bdda   Stefan Richter   ieee1394: replace...
869
870
871
  /* This size is arbitrarily chosen.
   * The struct overhead is subtracted for more economic allocations. */
  #define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
6c88e4756   Stefan Richter   ieee1394: remove ...
872

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
875
876
877
878
879
880
  int csr1212_generate_csr_image(struct csr1212_csr *csr)
  {
  	struct csr1212_bus_info_block_img *bi;
  	struct csr1212_csr_rom_cache *cache;
  	struct csr1212_keyval *kv;
  	size_t agg_size;
  	int ret;
  	int init_offset;
64ff71232   Stefan Richter   ieee1394: stricte...
881
  	BUG_ON(!csr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  
  	cache = csr->cache_head;
  
  	bi = (struct csr1212_bus_info_block_img*)cache->data;
  
  	bi->length = bytes_to_quads(csr->bus_info_len) - 1;
  	bi->crc_length = bi->length;
  	bi->crc = csr1212_crc16(bi->data, bi->crc_length);
  
  	csr->root_kv->next = NULL;
  	csr->root_kv->prev = NULL;
  
  	agg_size = csr1212_generate_layout_order(csr->root_kv);
  
  	init_offset = csr->bus_info_len;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
897
898
899
  	for (kv = csr->root_kv, cache = csr->cache_head;
  	     kv;
  	     cache = cache->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
901
902
903
904
  		if (!cache) {
  			/* Estimate approximate number of additional cache
  			 * regions needed (it assumes that the cache holding
  			 * the first 1K Config ROM space always exists). */
  			int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
982610bd0   Stefan Richter   ieee1394: csr1212...
905
  						(2 * sizeof(u32))) + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
909
  
  			/* Add additional cache regions, extras will be
  			 * removed later */
  			for (; est_c; est_c--) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
910
911
  				ret = csr1212_append_new_cache(csr,
  						CSR1212_EXTENDED_ROM_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
915
916
917
918
919
920
921
922
  				if (ret != CSR1212_SUCCESS)
  					return ret;
  			}
  			/* Need to re-layout for additional cache regions */
  			agg_size = csr1212_generate_layout_order(csr->root_kv);
  			kv = csr->root_kv;
  			cache = csr->cache_head;
  			init_offset = csr->bus_info_len;
  		}
  		kv = csr1212_generate_positions(cache, kv, init_offset);
  		agg_size -= cache->len;
982610bd0   Stefan Richter   ieee1394: csr1212...
923
  		init_offset = sizeof(u32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
926
927
928
929
930
931
932
933
934
935
  	}
  
  	/* Remove unused, excess cache regions */
  	while (cache) {
  		struct csr1212_csr_rom_cache *oc = cache;
  
  		cache = cache->next;
  		csr1212_remove_cache(csr, oc);
  	}
  
  	/* Go through the list backward so that when done, the correct CRC
  	 * will be calculated for the Extended ROM areas. */
c868ae2a1   Stefan Richter   ieee1394: csr1212...
936
  	for (cache = csr->cache_tail; cache; cache = cache->prev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
939
940
941
942
  		/* Only Extended ROM caches should have this set. */
  		if (cache->ext_rom) {
  			int leaf_size;
  
  			/* Make sure the Extended ROM leaf is a multiple of
  			 * max_rom in size. */
64ff71232   Stefan Richter   ieee1394: stricte...
943
  			BUG_ON(csr->max_rom < 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
946
947
948
949
950
951
  			leaf_size = (cache->len + (csr->max_rom - 1)) &
  				~(csr->max_rom - 1);
  
  			/* Zero out the unused ROM region */
  			memset(cache->data + bytes_to_quads(cache->len), 0x00,
  			       leaf_size - cache->len);
  
  			/* Subtract leaf header */
982610bd0   Stefan Richter   ieee1394: csr1212...
952
  			leaf_size -= sizeof(u32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
  
  			/* Update the Extended ROM leaf length */
  			cache->ext_rom->value.leaf.len =
  				bytes_to_quads(leaf_size);
  		} else {
  			/* Zero out the unused ROM region */
  			memset(cache->data + bytes_to_quads(cache->len), 0x00,
  			       cache->size - cache->len);
  		}
  
  		/* Copy the data into the cache buffer */
  		csr1212_fill_cache(cache);
  
  		if (cache != csr->cache_head) {
  			/* Set the length and CRC of the extended ROM. */
  			struct csr1212_keyval_img *kvi =
  				(struct csr1212_keyval_img*)cache->data;
982610bd0   Stefan Richter   ieee1394: csr1212...
970
  			u16 len = bytes_to_quads(cache->len) - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971

7fb9addba   Stefan Richter   ieee1394: drop cs...
972
973
  			kvi->length = cpu_to_be16(len);
  			kvi->crc = csr1212_crc16(kvi->data, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
976
977
978
  		}
  	}
  
  	return CSR1212_SUCCESS;
  }
982610bd0   Stefan Richter   ieee1394: csr1212...
979
  int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
  {
  	struct csr1212_csr_rom_cache *cache;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
982
  	for (cache = csr->cache_head; cache; cache = cache->next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
  		if (offset >= cache->offset &&
  		    (offset + len) <= (cache->offset + cache->size)) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
985
986
  			memcpy(buffer, &cache->data[
  					bytes_to_quads(offset - cache->offset)],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
988
989
  			       len);
  			return CSR1212_SUCCESS;
  		}
c868ae2a1   Stefan Richter   ieee1394: csr1212...
990

7fb9addba   Stefan Richter   ieee1394: drop cs...
991
  	return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
  }
fde675fa2   Stefan Richter   ieee1394: reduce ...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  /*
   * Apparently there are many different wrong implementations of the CRC
   * algorithm.  We don't fail, we just warn... approximately once per GUID.
   */
  static void
  csr1212_check_crc(const u32 *buffer, size_t length, u16 crc, __be32 *guid)
  {
  	static u64 last_bad_eui64;
  	u64 eui64 = ((u64)be32_to_cpu(guid[0]) << 32) | be32_to_cpu(guid[1]);
  
  	if (csr1212_crc16(buffer, length) == crc ||
  	    csr1212_msft_crc16(buffer, length) == crc ||
  	    eui64 == last_bad_eui64)
  		return;
  
  	printk(KERN_DEBUG "ieee1394: config ROM CRC error
  ");
  	last_bad_eui64 = eui64;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
1015
1016
1017
1018
1019
1020
  /* Parse a chunk of data as a Config ROM */
  
  static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
  {
  	struct csr1212_bus_info_block_img *bi;
  	struct csr1212_cache_region *cr;
  	int i;
  	int ret;
982610bd0   Stefan Richter   ieee1394: csr1212...
1021
  	for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
  		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
0bed18196   Stefan Richter   ieee1394: ignore ...
1023
1024
  				&csr->cache_head->data[bytes_to_quads(i)],
  				csr->private);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
1026
  		if (ret != CSR1212_SUCCESS)
  			return ret;
b2051f887   Stefan Richter   ieee1394: nodemgr...
1027
1028
1029
  
  		/* check ROM header's info_length */
  		if (i == 0 &&
7fb9addba   Stefan Richter   ieee1394: drop cs...
1030
  		    be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
b2051f887   Stefan Richter   ieee1394: nodemgr...
1031
  		    bytes_to_quads(csr->bus_info_len) - 1)
7fb9addba   Stefan Richter   ieee1394: drop cs...
1032
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
  	}
  
  	bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
  	csr->crc_len = quads_to_bytes(bi->crc_length);
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1037
1038
1039
  	/* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
  	 * is not always the case, so read the rest of the crc area 1 quadlet at
  	 * a time. */
982610bd0   Stefan Richter   ieee1394: csr1212...
1040
  	for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
  		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
0bed18196   Stefan Richter   ieee1394: ignore ...
1042
1043
  				&csr->cache_head->data[bytes_to_quads(i)],
  				csr->private);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
  		if (ret != CSR1212_SUCCESS)
  			return ret;
  	}
fde675fa2   Stefan Richter   ieee1394: reduce ...
1047
1048
  	csr1212_check_crc(bi->data, bi->crc_length, bi->crc,
  			  &csr->bus_info_data[3]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049

8551158ab   Stefan Richter   kmalloc/kzalloc c...
1050
  	cr = CSR1212_MALLOC(sizeof(*cr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
  	if (!cr)
7fb9addba   Stefan Richter   ieee1394: drop cs...
1052
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  
  	cr->next = NULL;
  	cr->prev = NULL;
  	cr->offset_start = 0;
  	cr->offset_end = csr->crc_len + 4;
  
  	csr->cache_head->filled_head = cr;
  	csr->cache_head->filled_tail = cr;
  
  	return CSR1212_SUCCESS;
  }
7fb9addba   Stefan Richter   ieee1394: drop cs...
1064
  #define CSR1212_KV_KEY(q)	(be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
6c88e4756   Stefan Richter   ieee1394: remove ...
1065
1066
1067
  #define CSR1212_KV_KEY_TYPE(q)	(CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
  #define CSR1212_KV_KEY_ID(q)	(CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
  #define CSR1212_KV_VAL_MASK	0xffffff
7fb9addba   Stefan Richter   ieee1394: drop cs...
1068
  #define CSR1212_KV_VAL(q)	(be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
6c88e4756   Stefan Richter   ieee1394: remove ...
1069

c868ae2a1   Stefan Richter   ieee1394: csr1212...
1070
1071
  static int
  csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1072
1073
1074
  {
  	int ret = CSR1212_SUCCESS;
  	struct csr1212_keyval *k = NULL;
982610bd0   Stefan Richter   ieee1394: csr1212...
1075
  	u32 offset;
17a19b795   Stefan Richter   ieee1394: csr1212...
1076
  	bool keep_keyval = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077

c868ae2a1   Stefan Richter   ieee1394: csr1212...
1078
  	switch (CSR1212_KV_KEY_TYPE(ki)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
1081
1082
  	case CSR1212_KV_TYPE_IMMEDIATE:
  		k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
  					  CSR1212_KV_VAL(ki));
  		if (!k) {
7fb9addba   Stefan Richter   ieee1394: drop cs...
1083
  			ret = -ENOMEM;
511f7b322   Stefan Richter   ieee1394: csr1212...
1084
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
  		}
17a19b795   Stefan Richter   ieee1394: csr1212...
1086
1087
  		/* Don't keep local reference when parsing. */
  		keep_keyval = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
1091
1092
1093
  		break;
  
  	case CSR1212_KV_TYPE_CSR_OFFSET:
  		k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
  					   CSR1212_KV_VAL(ki));
  		if (!k) {
7fb9addba   Stefan Richter   ieee1394: drop cs...
1094
  			ret = -ENOMEM;
511f7b322   Stefan Richter   ieee1394: csr1212...
1095
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
  		}
17a19b795   Stefan Richter   ieee1394: csr1212...
1097
1098
  		/* Don't keep local reference when parsing. */
  		keep_keyval = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
1100
1101
1102
1103
1104
1105
1106
1107
  		break;
  
  	default:
  		/* Compute the offset from 0xffff f000 0000. */
  		offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
  		if (offset == kv_pos) {
  			/* Uh-oh.  Can't have a relative offset of 0 for Leaves
  			 * or Directories.  The Config ROM image is most likely
  			 * messed up, so we'll just abort here. */
7fb9addba   Stefan Richter   ieee1394: drop cs...
1108
  			ret = -EIO;
511f7b322   Stefan Richter   ieee1394: csr1212...
1109
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
1113
1114
1115
  		}
  
  		k = csr1212_find_keyval_offset(dir, offset);
  
  		if (k)
  			break;		/* Found it. */
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1116
  		if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
  			k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1118
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
  			k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1120

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  		if (!k) {
7fb9addba   Stefan Richter   ieee1394: drop cs...
1122
  			ret = -ENOMEM;
511f7b322   Stefan Richter   ieee1394: csr1212...
1123
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
  		}
17a19b795   Stefan Richter   ieee1394: csr1212...
1125
1126
1127
1128
  		/* Don't keep local reference when parsing. */
  		keep_keyval = false;
  		/* Contents not read yet so it's not valid. */
  		k->valid = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
1132
1133
1134
1135
  		k->offset = offset;
  
  		k->prev = dir;
  		k->next = dir->next;
  		dir->next->prev = k;
  		dir->next = k;
  	}
17a19b795   Stefan Richter   ieee1394: csr1212...
1136
  	ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval);
511f7b322   Stefan Richter   ieee1394: csr1212...
1137
  out:
6c88e4756   Stefan Richter   ieee1394: remove ...
1138
1139
  	if (ret != CSR1212_SUCCESS && k != NULL)
  		free_keyval(k);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
1144
1145
1146
1147
1148
  int csr1212_parse_keyval(struct csr1212_keyval *kv,
  			 struct csr1212_csr_rom_cache *cache)
  {
  	struct csr1212_keyval_img *kvi;
  	int i;
  	int ret = CSR1212_SUCCESS;
  	int kvi_len;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1149
1150
  	kvi = (struct csr1212_keyval_img*)
  		&cache->data[bytes_to_quads(kv->offset - cache->offset)];
7fb9addba   Stefan Richter   ieee1394: drop cs...
1151
  	kvi_len = be16_to_cpu(kvi->length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152

fde675fa2   Stefan Richter   ieee1394: reduce ...
1153
1154
  	/* GUID is wrong in here in case of extended ROM.  We don't care. */
  	csr1212_check_crc(kvi->data, kvi_len, kvi->crc, &cache->data[3]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155

c868ae2a1   Stefan Richter   ieee1394: csr1212...
1156
  	switch (kv->key.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
  	case CSR1212_KV_TYPE_DIRECTORY:
  		for (i = 0; i < kvi_len; i++) {
982610bd0   Stefan Richter   ieee1394: csr1212...
1159
  			u32 ki = kvi->data[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
1161
1162
1163
1164
1165
1166
  
  			/* Some devices put null entries in their unit
  			 * directories.  If we come across such an entry,
  			 * then skip it. */
  			if (ki == 0x0)
  				continue;
  			ret = csr1212_parse_dir_entry(kv, ki,
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1167
  					kv->offset + quads_to_bytes(i + 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
1169
1170
1171
1172
1173
  		}
  		kv->value.directory.len = kvi_len;
  		break;
  
  	case CSR1212_KV_TYPE_LEAF:
  		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1174
1175
1176
  			size_t size = quads_to_bytes(kvi_len);
  
  			kv->value.leaf.data = CSR1212_MALLOC(size);
8551158ab   Stefan Richter   kmalloc/kzalloc c...
1177
  			if (!kv->value.leaf.data) {
7fb9addba   Stefan Richter   ieee1394: drop cs...
1178
  				ret = -ENOMEM;
511f7b322   Stefan Richter   ieee1394: csr1212...
1179
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
1182
  			}
  
  			kv->value.leaf.len = kvi_len;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1183
  			memcpy(kv->value.leaf.data, kvi->data, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
1185
1186
1187
1188
  		}
  		break;
  	}
  
  	kv->valid = 1;
511f7b322   Stefan Richter   ieee1394: csr1212...
1189
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
1191
  	return ret;
  }
c1a37f2c6   Stefan Richter   ieee1394: de-inli...
1192
1193
  static int
  csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
1196
1197
1198
  {
  	struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
  	struct csr1212_keyval_img *kvi = NULL;
  	struct csr1212_csr_rom_cache *cache;
  	int cache_index;
982610bd0   Stefan Richter   ieee1394: csr1212...
1199
1200
1201
  	u64 addr;
  	u32 *cache_ptr;
  	u16 kv_len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1202

64ff71232   Stefan Richter   ieee1394: stricte...
1203
  	BUG_ON(!csr || !kv || csr->max_rom < 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
  
  	/* First find which cache the data should be in (or go in if not read
  	 * yet). */
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1207
  	for (cache = csr->cache_head; cache; cache = cache->next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
1209
1210
  		if (kv->offset >= cache->offset &&
  		    kv->offset < (cache->offset + cache->size))
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
1212
  
  	if (!cache) {
982610bd0   Stefan Richter   ieee1394: csr1212...
1213
  		u32 q, cache_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
1216
  
  		/* Only create a new cache for Extended ROM leaves. */
  		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
7fb9addba   Stefan Richter   ieee1394: drop cs...
1217
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
1219
1220
  
  		if (csr->ops->bus_read(csr,
  				       CSR1212_REGISTER_SPACE_BASE + kv->offset,
0bed18196   Stefan Richter   ieee1394: ignore ...
1221
  				       &q, csr->private))
7fb9addba   Stefan Richter   ieee1394: drop cs...
1222
  			return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223

7fb9addba   Stefan Richter   ieee1394: drop cs...
1224
  		kv->value.leaf.len = be32_to_cpu(q) >> 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
1227
1228
1229
1230
  
  		cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
  			      (csr->max_rom - 1)) & ~(csr->max_rom - 1);
  
  		cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
  		if (!cache)
7fb9addba   Stefan Richter   ieee1394: drop cs...
1231
  			return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
1233
1234
1235
1236
1237
1238
  
  		kv->value.leaf.data = &cache->data[1];
  		csr->cache_tail->next = cache;
  		cache->prev = csr->cache_tail;
  		cache->next = NULL;
  		csr->cache_tail = cache;
  		cache->filled_head =
8551158ab   Stefan Richter   kmalloc/kzalloc c...
1239
  			CSR1212_MALLOC(sizeof(*cache->filled_head));
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1240
  		if (!cache->filled_head)
7fb9addba   Stefan Richter   ieee1394: drop cs...
1241
  			return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
1243
  
  		cache->filled_head->offset_start = 0;
982610bd0   Stefan Richter   ieee1394: csr1212...
1244
  		cache->filled_head->offset_end = sizeof(u32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
  		cache->filled_tail = cache->filled_head;
  		cache->filled_head->next = NULL;
  		cache->filled_head->prev = NULL;
  		cache->data[0] = q;
  
  		/* Don't read the entire extended ROM now.  Pieces of it will
  		 * be read when entries inside it are read. */
  		return csr1212_parse_keyval(kv, cache);
  	}
  
  	cache_index = kv->offset - cache->offset;
  
  	/* Now seach read portions of the cache to see if it is there. */
  	for (cr = cache->filled_head; cr; cr = cr->next) {
  		if (cache_index < cr->offset_start) {
8551158ab   Stefan Richter   kmalloc/kzalloc c...
1260
  			newcr = CSR1212_MALLOC(sizeof(*newcr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
  			if (!newcr)
7fb9addba   Stefan Richter   ieee1394: drop cs...
1262
  				return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
  
  			newcr->offset_start = cache_index & ~(csr->max_rom - 1);
  			newcr->offset_end = newcr->offset_start;
  			newcr->next = cr;
  			newcr->prev = cr->prev;
  			cr->prev = newcr;
  			cr = newcr;
  			break;
  		} else if ((cache_index >= cr->offset_start) &&
  			   (cache_index < cr->offset_end)) {
  			kvi = (struct csr1212_keyval_img*)
  				(&cache->data[bytes_to_quads(cache_index)]);
7fb9addba   Stefan Richter   ieee1394: drop cs...
1275
  			kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
  			break;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1277
  		} else if (cache_index == cr->offset_end) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
  			break;
c868ae2a1   Stefan Richter   ieee1394: csr1212...
1279
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
1281
1282
1283
  	}
  
  	if (!cr) {
  		cr = cache->filled_tail;
8551158ab   Stefan Richter   kmalloc/kzalloc c...
1284
  		newcr = CSR1212_MALLOC(sizeof(*newcr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
  		if (!newcr)
7fb9addba   Stefan Richter   ieee1394: drop cs...
1286
  			return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
  
  		newcr->offset_start = cache_index & ~(csr->max_rom - 1);
  		newcr->offset_end = newcr->offset_start;
  		newcr->prev = cr;
  		newcr->next = cr->next;
  		cr->next = newcr;
  		cr = newcr;
  		cache->filled_tail = newcr;
  	}
  
  	while(!kvi || cr->offset_end < cache_index + kv_len) {
  		cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
  							~(csr->max_rom - 1))];
  
  		addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
  			cr->offset_end) & ~(csr->max_rom - 1);
0bed18196   Stefan Richter   ieee1394: ignore ...
1303
1304
  		if (csr->ops->bus_read(csr, addr, cache_ptr, csr->private))
  			return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1305
1306
1307
1308
1309
1310
1311
  
  		cr->offset_end += csr->max_rom - (cr->offset_end &
  						  (csr->max_rom - 1));
  
  		if (!kvi && (cr->offset_end > cache_index)) {
  			kvi = (struct csr1212_keyval_img*)
  				(&cache->data[bytes_to_quads(cache_index)]);
7fb9addba   Stefan Richter   ieee1394: drop cs...
1312
  			kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
1314
1315
1316
1317
1318
1319
  		}
  
  		if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
  			/* The Leaf or Directory claims its length extends
  			 * beyond the ConfigROM image region and thus beyond the
  			 * end of our cache region.  Therefore, we abort now
  			 * rather than seg faulting later. */
7fb9addba   Stefan Richter   ieee1394: drop cs...
1320
  			return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
  		}
  
  		ncr = cr->next;
  
  		if (ncr && (cr->offset_end >= ncr->offset_start)) {
  			/* consolidate region entries */
  			ncr->offset_start = cr->offset_start;
  
  			if (cr->prev)
  				cr->prev->next = cr->next;
  			ncr->prev = cr->prev;
  			if (cache->filled_head == cr)
  				cache->filled_head = ncr;
  			CSR1212_FREE(cr);
  			cr = ncr;
  		}
  	}
  
  	return csr1212_parse_keyval(kv, cache);
  }
c1a37f2c6   Stefan Richter   ieee1394: de-inli...
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
  struct csr1212_keyval *
  csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
  {
  	if (!kv)
  		return NULL;
  	if (!kv->valid)
  		if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
  			return NULL;
  	return kv;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1351
1352
  int csr1212_parse_csr(struct csr1212_csr *csr)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
1354
  	struct csr1212_dentry *dentry;
  	int ret;
64ff71232   Stefan Richter   ieee1394: stricte...
1355
  	BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
1357
1358
1359
  
  	ret = csr1212_parse_bus_info_block(csr);
  	if (ret != CSR1212_SUCCESS)
  		return ret;
0bed18196   Stefan Richter   ieee1394: ignore ...
1360
1361
1362
1363
1364
1365
1366
  	/*
  	 * There has been a buggy firmware with bus_info_block.max_rom > 0
  	 * spotted which actually only supported quadlet read requests to the
  	 * config ROM.  Therefore read everything quadlet by quadlet regardless
  	 * of what the bus info block says.
  	 */
  	csr->max_rom = 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
  
  	csr->cache_head->layout_head = csr->root_kv;
  	csr->cache_head->layout_tail = csr->root_kv;
  
  	csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
  		csr->bus_info_len;
  
  	csr->root_kv->valid = 0;
  	csr->root_kv->next = csr->root_kv;
  	csr->root_kv->prev = csr->root_kv;
c1a37f2c6   Stefan Richter   ieee1394: de-inli...
1377
  	ret = csr1212_read_keyval(csr, csr->root_kv);
5303a986c   Jody McIntyre   csr1212: check re...
1378
1379
  	if (ret != CSR1212_SUCCESS)
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
1381
1382
1383
1384
  
  	/* Scan through the Root directory finding all extended ROM regions
  	 * and make cache regions for them */
  	for (dentry = csr->root_kv->value.directory.dentries_head;
  	     dentry; dentry = dentry->next) {
a96074e76   Jody McIntyre   csr1212: add chec...
1385
1386
  		if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
  			!dentry->kv->valid) {
c1a37f2c6   Stefan Richter   ieee1394: de-inli...
1387
  			ret = csr1212_read_keyval(csr, dentry->kv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1388
1389
1390
1391
1392
1393
1394
  			if (ret != CSR1212_SUCCESS)
  				return ret;
  		}
  	}
  
  	return CSR1212_SUCCESS;
  }