@@ -59,6 +59,67 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
59
59
}
60
60
EXPORT_SYMBOL (fw_csr_iterator_next );
61
61
62
+ static u32 * search_leaf (u32 * directory , int search_key )
63
+ {
64
+ struct fw_csr_iterator ci ;
65
+ int last_key = 0 , key , value ;
66
+
67
+ fw_csr_iterator_init (& ci , directory );
68
+ while (fw_csr_iterator_next (& ci , & key , & value )) {
69
+ if (last_key == search_key &&
70
+ key == (CSR_DESCRIPTOR | CSR_LEAF ))
71
+ return ci .p - 1 + value ;
72
+ last_key = key ;
73
+ }
74
+ return NULL ;
75
+ }
76
+
77
+ static int textual_leaf_to_string (u32 * block , char * buf , size_t size )
78
+ {
79
+ unsigned int quadlets , length ;
80
+
81
+ if (!size || !buf )
82
+ return - EINVAL ;
83
+
84
+ quadlets = min (block [0 ] >> 16 , 256u );
85
+ if (quadlets < 2 )
86
+ return - ENODATA ;
87
+
88
+ if (block [1 ] != 0 || block [2 ] != 0 )
89
+ /* unknown language/character set */
90
+ return - ENODATA ;
91
+
92
+ block += 3 ;
93
+ quadlets -= 2 ;
94
+ for (length = 0 ; length < quadlets * 4 && length + 1 < size ; length ++ ) {
95
+ char c = block [length / 4 ] >> (24 - 8 * (length % 4 ));
96
+ if (c == '\0' )
97
+ break ;
98
+ buf [length ] = c ;
99
+ }
100
+ buf [length ] = '\0' ;
101
+ return length ;
102
+ }
103
+
104
+ /**
105
+ * fw_csr_string - reads a string from the configuration ROM
106
+ * @directory: device or unit directory;
107
+ * fw_device->config_rom+5 or fw_unit->directory
108
+ * @key: the key of the preceding directory entry
109
+ * @buf: where to put the string
110
+ * @size: size of @buf, in bytes
111
+ *
112
+ * Returns string length (>= 0) or error code (< 0).
113
+ */
114
+ int fw_csr_string (u32 * directory , int key , char * buf , size_t size )
115
+ {
116
+ u32 * leaf = search_leaf (directory , key );
117
+ if (!leaf )
118
+ return - ENOENT ;
119
+ return textual_leaf_to_string (leaf , buf , size );
120
+ }
121
+ EXPORT_SYMBOL (fw_csr_string );
122
+
62
123
static bool is_fw_unit (struct device * dev );
63
124
64
125
static int match_unit_directory (u32 * directory , u32 match_flags ,
@@ -226,10 +287,10 @@ static ssize_t show_text_leaf(struct device *dev,
226
287
{
227
288
struct config_rom_attribute * attr =
228
289
container_of (dattr , struct config_rom_attribute , attr );
229
- struct fw_csr_iterator ci ;
230
- u32 * dir , * block = NULL , * p , * end ;
231
- int length , key , value , last_key = 0 , ret = - ENOENT ;
232
- char * b ;
290
+ u32 * dir ;
291
+ size_t bufsize ;
292
+ char dummy_buf [ 2 ] ;
293
+ int ret ;
233
294
234
295
down_read (& fw_device_rwsem );
235
296
@@ -238,40 +299,23 @@ static ssize_t show_text_leaf(struct device *dev,
238
299
else
239
300
dir = fw_device (dev )-> config_rom + 5 ;
240
301
241
- fw_csr_iterator_init (& ci , dir );
242
- while (fw_csr_iterator_next (& ci , & key , & value )) {
243
- if (attr -> key == last_key &&
244
- key == (CSR_DESCRIPTOR | CSR_LEAF ))
245
- block = ci .p - 1 + value ;
246
- last_key = key ;
302
+ if (buf ) {
303
+ bufsize = PAGE_SIZE - 1 ;
304
+ } else {
305
+ buf = dummy_buf ;
306
+ bufsize = 1 ;
247
307
}
248
308
249
- if (block == NULL )
250
- goto out ;
251
-
252
- length = min (block [0 ] >> 16 , 256U );
253
- if (length < 3 )
254
- goto out ;
255
-
256
- if (block [1 ] != 0 || block [2 ] != 0 )
257
- /* Unknown encoding. */
258
- goto out ;
309
+ ret = fw_csr_string (dir , attr -> key , buf , bufsize );
259
310
260
- if (buf == NULL ) {
261
- ret = length * 4 ;
262
- goto out ;
311
+ if (ret >= 0 ) {
312
+ /* Strip trailing whitespace and add newline. */
313
+ while (ret > 0 && isspace (buf [ret - 1 ]))
314
+ ret -- ;
315
+ strcpy (buf + ret , "\n" );
316
+ ret ++ ;
263
317
}
264
318
265
- b = buf ;
266
- end = & block [length + 1 ];
267
- for (p = & block [3 ]; p < end ; p ++ , b += 4 )
268
- * (u32 * ) b = (__force u32 ) __cpu_to_be32 (* p );
269
-
270
- /* Strip trailing whitespace and add newline. */
271
- while (b -- , (isspace (* b ) || * b == '\0' ) && b > buf );
272
- strcpy (b + 1 , "\n" );
273
- ret = b + 2 - buf ;
274
- out :
275
319
up_read (& fw_device_rwsem );
276
320
277
321
return ret ;
0 commit comments