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