Add version to PATCH_LOG and LAST_LOG.
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / io / labelcl.c
1 /*  labelcl - SGI's Hwgraph Compatibility Layer.
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
8 */
9
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <asm/sn/sgi.h>
13 #include <linux/devfs_fs.h>
14 #include <linux/devfs_fs_kernel.h>
15 #include <asm/sn/invent.h>
16 #include <asm/sn/hcl.h>
17 #include <asm/sn/labelcl.h>
18
19 /*
20 ** Very simple and dumb string table that supports only find/insert.
21 ** In practice, if this table gets too large, we may need a more
22 ** efficient data structure.   Also note that currently there is no 
23 ** way to delete an item once it's added.  Therefore, name collision 
24 ** will return an error.
25 */
26
27 struct string_table label_string_table;
28
29
30
31 /*
32  * string_table_init - Initialize the given string table.
33  */
34 void
35 string_table_init(struct string_table *string_table)
36 {
37         string_table->string_table_head = NULL;
38         string_table->string_table_generation = 0;
39
40         /*
41          * We nedd to initialize locks here!
42          */
43
44         return;
45 }
46
47
48 /*
49  * string_table_destroy - Destroy the given string table.
50  */
51 void
52 string_table_destroy(struct string_table *string_table)
53 {
54         struct string_table_item *item, *next_item;
55
56         item = string_table->string_table_head;
57         while (item) {
58                 next_item = item->next;
59
60                 STRTBL_FREE(item);
61                 item = next_item;
62         }
63
64         /*
65          * We need to destroy whatever lock we have here
66          */
67
68         return;
69 }
70
71
72
73 /*
74  * string_table_insert - Insert an entry in the string table .. duplicate 
75  *      names are not allowed.
76  */
77 char *
78 string_table_insert(struct string_table *string_table, char *name)
79 {
80         struct string_table_item *item, *new_item = NULL, *last_item = NULL;
81
82 again:
83         /*
84          * Need to lock the table ..
85          */
86         item = string_table->string_table_head;
87         last_item = NULL;
88
89         while (item) {
90                 if (!strcmp(item->string, name)) {
91                         /*
92                          * If we allocated space for the string and the found that
93                          * someone else already entered it into the string table,
94                          * free the space we just allocated.
95                          */
96                         if (new_item)
97                                 STRTBL_FREE(new_item);
98
99
100                         /*
101                          * Search optimization: move the found item to the head
102                          * of the list.
103                          */
104                         if (last_item != NULL) {
105                                 last_item->next = item->next;
106                                 item->next = string_table->string_table_head;
107                                 string_table->string_table_head = item;
108                         }
109                         goto out;
110                 }
111                 last_item = item;
112                 item=item->next;
113         }
114
115         /*
116          * name was not found, so add it to the string table.
117          */
118         if (new_item == NULL) {
119                 long old_generation = string_table->string_table_generation;
120
121                 new_item = STRTBL_ALLOC(strlen(name));
122
123                 strcpy(new_item->string, name);
124
125                 /*
126                  * While we allocated memory for the new string, someone else 
127                  * changed the string table.
128                  */
129                 if (old_generation != string_table->string_table_generation) {
130                         goto again;
131                 }
132         } else {
133                 /* At this we only have the string table lock in access mode.
134                  * Promote the access lock to an update lock for the string
135                  * table insertion below.
136                  */
137                         long old_generation = 
138                                 string_table->string_table_generation;
139
140                         /*
141                          * After we did the unlock and wer waiting for update
142                          * lock someone could have potentially updated
143                          * the string table. Check the generation number
144                          * for this case. If it is the case we have to
145                          * try all over again.
146                          */
147                         if (old_generation != 
148                             string_table->string_table_generation) {
149                                 goto again;
150                         }
151                 }
152
153         /*
154          * At this point, we're committed to adding new_item to the string table.
155          */
156         new_item->next = string_table->string_table_head;
157         item = string_table->string_table_head = new_item;
158         string_table->string_table_generation++;
159
160 out:
161         /*
162          * Need to unlock here.
163          */
164         return(item->string);
165 }
166
167 /*
168  * labelcl_info_create - Creates the data structure that will hold the
169  *      device private information asscoiated with a devfs entry.
170  *      The pointer to this structure is what gets stored in the devfs 
171  *      (void * info).
172  */
173 labelcl_info_t *
174 labelcl_info_create()
175 {
176
177         labelcl_info_t *new = NULL;
178
179         /* Initial allocation does not include any area for labels */
180         if ( ( new = (labelcl_info_t *)kmalloc (sizeof(labelcl_info_t), GFP_KERNEL) ) == NULL )
181                 return NULL;
182
183         memset (new, 0, sizeof(labelcl_info_t));
184         new->hwcl_magic = LABELCL_MAGIC;
185         return( new);
186
187 }
188
189 /*
190  * labelcl_info_destroy - Frees the data structure that holds the
191  *      device private information asscoiated with a devfs entry.  This 
192  *      data structure was created by device_info_create().
193  *
194  *      The caller is responsible for nulling the (void *info) in the 
195  *      corresponding devfs entry.
196  */
197 int
198 labelcl_info_destroy(labelcl_info_t *labelcl_info)
199 {
200
201         if (labelcl_info == NULL)
202                 return(0);
203
204         /* Free the label list */
205         if (labelcl_info->label_list)
206                 kfree(labelcl_info->label_list);
207
208         /* Now free the label info area */
209         labelcl_info->hwcl_magic = 0;
210         kfree(labelcl_info);
211
212         return(0);
213 }
214
215 /*
216  * labelcl_info_add_LBL - Adds a new label entry in the labelcl info 
217  *      structure.
218  *
219  *      Error is returned if we find another label with the same name.
220  */
221 int
222 labelcl_info_add_LBL(devfs_handle_t de,
223                         char *info_name,
224                         arb_info_desc_t info_desc,
225                         arbitrary_info_t info)
226 {
227         labelcl_info_t  *labelcl_info = NULL;
228         int num_labels;
229         int new_label_list_size;
230         label_info_t *old_label_list, *new_label_list = NULL;
231         char *name;
232         int i;
233
234         if (de == NULL)
235                 return(-1);
236
237         labelcl_info = devfs_get_info(de);
238         if (labelcl_info == NULL)
239                 return(-1);
240
241         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
242                 return(-1);
243
244         if (info_name == NULL)
245                 return(-1);
246
247         if (strlen(info_name) >= LABEL_LENGTH_MAX)
248                 return(-1);
249
250         name = string_table_insert(&label_string_table, info_name);
251
252         num_labels = labelcl_info->num_labels;
253         new_label_list_size = sizeof(label_info_t) * (num_labels+1);
254
255         /*
256          * Create a new label info area.
257          */
258         if (new_label_list_size != 0) {
259                 new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL);
260
261                 if (new_label_list == NULL)
262                         return(-1);
263         }
264
265         /*
266          * At this point, we are committed to adding the labelled info, 
267          * if there isn't already information there with the same name.
268          */
269         old_label_list = labelcl_info->label_list;
270
271         /* 
272          * Look for matching info name.
273          */
274         for (i=0; i<num_labels; i++) {
275                 if (!strcmp(info_name, old_label_list[i].name)) {
276                         /* Not allowed to add duplicate labelled info names. */
277                         kfree(new_label_list);
278                         printk(KERN_WARNING "labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, (void *)de);
279                         return(-1);
280                 }
281                 new_label_list[i] = old_label_list[i]; /* structure copy */
282         }
283
284         new_label_list[num_labels].name = name;
285         new_label_list[num_labels].desc = info_desc;
286         new_label_list[num_labels].info = info;
287
288         labelcl_info->num_labels = num_labels+1;
289         labelcl_info->label_list = new_label_list;
290
291         if (old_label_list != NULL)
292                 kfree(old_label_list);
293
294         return(0);
295 }
296
297 /*
298  * labelcl_info_remove_LBL - Remove a label entry.
299  */
300 int
301 labelcl_info_remove_LBL(devfs_handle_t de,
302                          char *info_name,
303                          arb_info_desc_t *info_desc,
304                          arbitrary_info_t *info)
305 {
306         labelcl_info_t  *labelcl_info = NULL;
307         int num_labels;
308         int new_label_list_size;
309         label_info_t *old_label_list, *new_label_list = NULL;
310         arb_info_desc_t label_desc_found;
311         arbitrary_info_t label_info_found;
312         int i;
313
314         if (de == NULL)
315                 return(-1);
316
317         labelcl_info = devfs_get_info(de);
318         if (labelcl_info == NULL)
319                 return(-1);
320
321         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
322                 return(-1);
323
324         num_labels = labelcl_info->num_labels;
325         if (num_labels == 0) {
326                 return(-1);
327         }
328
329         /*
330          * Create a new info area.
331          */
332         new_label_list_size = sizeof(label_info_t) * (num_labels-1);
333         if (new_label_list_size) {
334                 new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL);
335                 if (new_label_list == NULL)
336                         return(-1);
337         }
338
339         /*
340          * At this point, we are committed to removing the labelled info, 
341          * if it still exists.
342          */
343         old_label_list = labelcl_info->label_list;
344
345         /* 
346          * Find matching info name.
347          */
348         for (i=0; i<num_labels; i++) {
349                 if (!strcmp(info_name, old_label_list[i].name)) {
350                         label_desc_found = old_label_list[i].desc;
351                         label_info_found = old_label_list[i].info;
352                         goto found;
353                 }
354                 if (i < num_labels-1) /* avoid walking off the end of the new vertex */
355                         new_label_list[i] = old_label_list[i]; /* structure copy */
356         }
357
358         /* The named info doesn't exist. */
359         if (new_label_list)
360                 kfree(new_label_list);
361
362         return(-1);
363
364 found:
365         /* Finish up rest of labelled info */
366         for (i=i+1; i<num_labels; i++)
367                 new_label_list[i-1] = old_label_list[i]; /* structure copy */
368
369         labelcl_info->num_labels = num_labels+1;
370         labelcl_info->label_list = new_label_list;
371
372         kfree(old_label_list);
373
374         if (info != NULL)
375                 *info = label_info_found;
376
377         if (info_desc != NULL)
378                 *info_desc = label_desc_found;
379
380         return(0);
381 }
382
383
384 /*
385  * labelcl_info_replace_LBL - Replace an existing label entry with the 
386  *      given new information.
387  *
388  *      Label entry must exist.
389  */
390 int
391 labelcl_info_replace_LBL(devfs_handle_t de,
392                         char *info_name,
393                         arb_info_desc_t info_desc,
394                         arbitrary_info_t info,
395                         arb_info_desc_t *old_info_desc,
396                         arbitrary_info_t *old_info)
397 {
398         labelcl_info_t  *labelcl_info = NULL;
399         int num_labels;
400         label_info_t *label_list;
401         int i;
402
403         if (de == NULL)
404                 return(-1);
405
406         labelcl_info = devfs_get_info(de);
407         if (labelcl_info == NULL)
408                 return(-1);
409
410         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
411                 return(-1);
412
413         num_labels = labelcl_info->num_labels;
414         if (num_labels == 0) {
415                 return(-1);
416         }
417
418         if (info_name == NULL)
419                 return(-1);
420
421         label_list = labelcl_info->label_list;
422
423         /* 
424          * Verify that information under info_name already exists.
425          */
426         for (i=0; i<num_labels; i++)
427                 if (!strcmp(info_name, label_list[i].name)) {
428                         if (old_info != NULL)
429                                 *old_info = label_list[i].info;
430
431                         if (old_info_desc != NULL)
432                                 *old_info_desc = label_list[i].desc;
433
434                         label_list[i].info = info;
435                         label_list[i].desc = info_desc;
436
437                         return(0);
438                 }
439
440
441         return(-1);
442 }
443
444 /*
445  * labelcl_info_get_LBL - Retrieve and return the information for the 
446  *      given label entry.
447  */
448 int
449 labelcl_info_get_LBL(devfs_handle_t de,
450                       char *info_name,
451                       arb_info_desc_t *info_desc,
452                       arbitrary_info_t *info)
453 {
454         labelcl_info_t  *labelcl_info = NULL;
455         int num_labels;
456         label_info_t *label_list;
457         int i;
458
459         if (de == NULL)
460                 return(-1);
461
462         labelcl_info = devfs_get_info(de);
463         if (labelcl_info == NULL)
464                 return(-1);
465
466         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
467                 return(-1);
468
469         num_labels = labelcl_info->num_labels;
470         if (num_labels == 0) {
471                 return(-1);
472         }
473
474         label_list = labelcl_info->label_list;
475
476         /* 
477          * Find information under info_name.
478          */
479         for (i=0; i<num_labels; i++)
480                 if (!strcmp(info_name, label_list[i].name)) {
481                         if (info != NULL)
482                                 *info = label_list[i].info;
483                         if (info_desc != NULL)
484                                 *info_desc = label_list[i].desc;
485
486                         return(0);
487                 }
488
489         return(-1);
490 }
491
492 /*
493  * labelcl_info_get_next_LBL - returns the next label entry on the list.
494  */
495 int
496 labelcl_info_get_next_LBL(devfs_handle_t de,
497                            char *buffer,
498                            arb_info_desc_t *info_descp,
499                            arbitrary_info_t *infop,
500                            labelcl_info_place_t *placeptr)
501 {
502         labelcl_info_t  *labelcl_info = NULL;
503         uint which_info;
504         label_info_t *label_list;
505
506         if ((buffer == NULL) && (infop == NULL))
507                 return(-1);
508
509         if (placeptr == NULL)
510                 return(-1);
511
512         if (de == NULL)
513                 return(-1);
514
515         labelcl_info = devfs_get_info(de);
516         if (labelcl_info == NULL)
517                 return(-1);
518
519         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
520                 return(-1);
521
522         which_info = *placeptr;
523
524         if (which_info >= labelcl_info->num_labels) {
525                 return(-1);
526         }
527
528         label_list = (label_info_t *) labelcl_info->label_list;
529
530         if (buffer != NULL)
531                 strcpy(buffer, label_list[which_info].name);
532
533         if (infop)
534                 *infop = label_list[which_info].info;
535
536         if (info_descp)
537                 *info_descp = label_list[which_info].desc;
538
539         *placeptr = which_info + 1;
540
541         return(0);
542 }
543
544
545 int
546 labelcl_info_replace_IDX(devfs_handle_t de,
547                         int index,
548                         arbitrary_info_t info,
549                         arbitrary_info_t *old_info)
550 {
551         arbitrary_info_t *info_list_IDX;
552         labelcl_info_t  *labelcl_info = NULL;
553
554         if (de == NULL) {
555                 printk(KERN_ALERT "labelcl: NULL devfs handle given.\n");
556                 return(-1);
557         }
558
559         labelcl_info = devfs_get_info(de);
560         if (labelcl_info == NULL) {
561                 printk(KERN_ALERT "labelcl: Entry does not have info pointer.\n");
562                 return(-1);
563         }
564
565         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
566                 return(-1);
567
568         if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) )
569                 return(-1);
570
571         /*
572          * Replace information at the appropriate index in this vertex with 
573          * the new info.
574          */
575         info_list_IDX = labelcl_info->IDX_list;
576         if (old_info != NULL)
577                 *old_info = info_list_IDX[index];
578         info_list_IDX[index] = info;
579
580         return(0);
581
582 }
583
584 /*
585  * labelcl_info_connectpt_set - Sets the connectpt.
586  */
587 int
588 labelcl_info_connectpt_set(struct devfs_entry *de,
589                           struct devfs_entry *connect_de)
590 {
591         arbitrary_info_t old_info;
592         int     rv;
593
594         rv = labelcl_info_replace_IDX(de, HWGRAPH_CONNECTPT, 
595                 (arbitrary_info_t) connect_de, &old_info);
596
597         if (rv) {
598                 return(rv);
599         }
600
601         return(0);
602 }
603
604
605 /*
606  * labelcl_info_get_IDX - Returns the information pointed at by index.
607  *
608  */
609 int
610 labelcl_info_get_IDX(devfs_handle_t de,
611                         int index,
612                         arbitrary_info_t *info)
613 {
614         arbitrary_info_t *info_list_IDX;
615         labelcl_info_t  *labelcl_info = NULL;
616
617         if (de == NULL)
618                 return(-1);
619
620         labelcl_info = devfs_get_info(de);
621         if (labelcl_info == NULL)
622                 return(-1);
623
624         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
625                 return(-1);
626
627         if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) )
628                 return(-1);
629
630         /*
631          * Return information at the appropriate index in this vertex.
632          */
633         info_list_IDX = labelcl_info->IDX_list;
634         if (info != NULL)
635                 *info = info_list_IDX[index];
636
637         return(0);
638 }
639
640 /*
641  * labelcl_info_connectpt_get - Retrieve the connect point for a device entry.
642  */
643 struct devfs_entry *
644 labelcl_info_connectpt_get(struct devfs_entry *de)
645 {
646         int rv;
647         arbitrary_info_t info;
648
649         rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info);
650         if (rv)
651                 return(NULL);
652
653         return((struct devfs_entry *)info);
654 }