1 /* uisutils.c
2  *
3  * Copyright (C) 2010 - 2013 UNISYS CORPORATION
4  * All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14  * NON INFRINGEMENT.  See the GNU General Public License for more
15  * details.
16  */
17 
18 #include <linux/string.h>
19 #include <linux/slab.h>
20 #include <linux/types.h>
21 #include <linux/uuid.h>
22 #include <linux/spinlock.h>
23 #include <linux/list.h>
24 #include "uisutils.h"
25 #include "version.h"
26 #include "vbushelper.h"
27 #include <linux/skbuff.h>
28 #ifdef CONFIG_HIGHMEM
29 #include <linux/highmem.h>
30 #endif
31 
32 /* this is shorter than using __FILE__ (full path name) in
33  * debug/info/error messages
34  */
35 #define CURRENT_FILE_PC UISLIB_PC_uisutils_c
36 #define __MYFILE__ "uisutils.c"
37 
38 /* exports */
39 atomic_t uisutils_registered_services = ATOMIC_INIT(0);
40 					/* num registrations via
41 					 * uisctrl_register_req_handler() or
42 					 * uisctrl_register_req_handler_ex() */
43 
44 /*****************************************************/
45 /* Utility functions                                 */
46 /*****************************************************/
47 
48 int
uisutil_add_proc_line_ex(int * total,char ** buffer,int * buffer_remaining,char * format,...)49 uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
50 			 char *format, ...)
51 {
52 	va_list args;
53 	int len;
54 
55 	va_start(args, format);
56 	len = vsnprintf(*buffer, *buffer_remaining, format, args);
57 	va_end(args);
58 	if (len >= *buffer_remaining) {
59 		*buffer += *buffer_remaining;
60 		*total += *buffer_remaining;
61 		*buffer_remaining = 0;
62 		return -1;
63 	}
64 	*buffer_remaining -= len;
65 	*buffer += len;
66 	*total += len;
67 	return len;
68 }
69 EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex);
70 
71 int
uisctrl_register_req_handler(int type,void * fptr,struct ultra_vbus_deviceinfo * chipset_driver_info)72 uisctrl_register_req_handler(int type, void *fptr,
73 			     struct ultra_vbus_deviceinfo *chipset_driver_info)
74 {
75 	switch (type) {
76 	case 2:
77 		if (fptr) {
78 			if (!virt_control_chan_func)
79 				atomic_inc(&uisutils_registered_services);
80 			virt_control_chan_func = fptr;
81 		} else {
82 			if (virt_control_chan_func)
83 				atomic_dec(&uisutils_registered_services);
84 			virt_control_chan_func = NULL;
85 		}
86 		break;
87 
88 	default:
89 		return 0;
90 	}
91 	if (chipset_driver_info)
92 		bus_device_info_init(chipset_driver_info, "chipset", "uislib",
93 				     VERSION, NULL);
94 
95 	return 1;
96 }
97 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler);
98 
99 /*
100  * unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
101  *					     void *skb_in,
102  *					     unsigned int firstfraglen,
103  *					     unsigned int frags_max,
104  *					     struct phys_info frags[])
105  *
106  *	calling_ctx - input -   a string that is displayed to show
107  *				who called * this func
108  *	void *skb_in -  skb whose frag info we're copying type is hidden so we
109  *			don't need to include skbbuff in uisutils.h which is
110  *			included in non-networking code.
111  *	unsigned int firstfraglen - input - length of first fragment in skb
112  *	unsigned int frags_max - input - max len of frags array
113  *	struct phys_info frags[] - output - frags array filled in on output
114  *					    return value indicates number of
115  *					    entries filled in frags
116  */
117 
118 static LIST_HEAD(req_handler_info_list); /* list of struct req_handler_info */
119 static DEFINE_SPINLOCK(req_handler_info_list_lock);
120 
121 struct req_handler_info *
req_handler_find(uuid_le switch_uuid)122 req_handler_find(uuid_le switch_uuid)
123 {
124 	struct list_head *lelt, *tmp;
125 	struct req_handler_info *entry = NULL;
126 
127 	spin_lock(&req_handler_info_list_lock);
128 	list_for_each_safe(lelt, tmp, &req_handler_info_list) {
129 		entry = list_entry(lelt, struct req_handler_info, list_link);
130 		if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
131 			spin_unlock(&req_handler_info_list_lock);
132 			return entry;
133 		}
134 	}
135 	spin_unlock(&req_handler_info_list_lock);
136 	return NULL;
137 }
138