• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2010 - 2013 UNISYS CORPORATION
2  * All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or (at
7  * your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
12  * NON INFRINGEMENT.  See the GNU General Public License for more
13  * details.
14  */
15 
16 #ifndef __VBUSDEVICEINFO_H__
17 #define __VBUSDEVICEINFO_H__
18 
19 #include <linux/types.h>
20 
21 #pragma pack(push, 1)		/* both GCC and VC now allow this pragma */
22 
23 /* An array of this struct is present in the channel area for each vbus.
24  * (See vbuschannel.h.)
25  * It is filled in by the client side to provide info about the device
26  * and driver from the client's perspective.
27  */
28 typedef struct _ULTRA_VBUS_DEVICEINFO {
29 	u8 devType[16];		/* short string identifying the device type */
30 	u8 drvName[16];		/* driver .sys file name */
31 	u8 infoStrings[96];	/* sequence of tab-delimited id strings: */
32 	/* <DRIVER_REV> <DRIVER_VERTAG> <DRIVER_COMPILETIME> */
33 	u8 reserved[128];	/* pad size to 256 bytes */
34 } ULTRA_VBUS_DEVICEINFO;
35 
36 #pragma pack(pop)
37 
38 /* Reads chars from the buffer at <src> for <srcmax> bytes, and writes to
39  * the buffer at <p>, which is <remain> bytes long, ensuring never to
40  * overflow the buffer at <p>, using the following rules:
41  * - printable characters are simply copied from the buffer at <src> to the
42  *   buffer at <p>
43  * - intervening streaks of non-printable characters in the buffer at <src>
44  *   are replaced with a single space in the buffer at <p>
45  * Note that we pay no attention to '\0'-termination.
46  * Returns the number of bytes written to <p>.
47  *
48  * Pass <p> == NULL and <remain> == 0 for this special behavior.  In this
49  * case, we simply return the number of bytes that WOULD HAVE been written
50  * to a buffer at <p>, had it been infinitely big.
51  */
52 static inline int
vbuschannel_sanitize_buffer(char * p,int remain,char * src,int srcmax)53 vbuschannel_sanitize_buffer(char *p, int remain, char *src, int srcmax)
54 {
55 	int chars = 0;
56 	int nonprintable_streak = 0;
57 
58 	while (srcmax > 0) {
59 		if ((*src >= ' ') && (*src < 0x7f)) {
60 			if (nonprintable_streak) {
61 				if (remain > 0) {
62 					*p = ' ';
63 					p++;
64 					remain--;
65 					chars++;
66 				} else if (p == NULL)
67 					chars++;
68 				nonprintable_streak = 0;
69 			}
70 			if (remain > 0) {
71 				*p = *src;
72 				p++;
73 				remain--;
74 				chars++;
75 			} else if (p == NULL)
76 				chars++;
77 		} else
78 			nonprintable_streak = 1;
79 		src++;
80 		srcmax--;
81 	}
82 	return chars;
83 }
84 
85 #define VBUSCHANNEL_ADDACHAR(ch, p, remain, chars) \
86 	do {					   \
87 		if (remain <= 0)		   \
88 			break;			   \
89 		*p = ch;			   \
90 		p++;  chars++;  remain--;	   \
91 	} while (0)
92 
93 /* Converts the non-negative value at <num> to an ascii decimal string
94  * at <p>, writing at most <remain> bytes.  Note there is NO '\0' termination
95  * written to <p>.
96  *
97  * Returns the number of bytes written to <p>.
98  *
99  * Note that we create this function because we need to do this operation in
100  * an environment-independent way (since we are in a common header file).
101  */
102 static inline int
vbuschannel_itoa(char * p,int remain,int num)103 vbuschannel_itoa(char *p, int remain, int num)
104 {
105 	int digits = 0;
106 	char s[32];
107 	int i;
108 
109 	if (num == 0) {
110 		/* '0' is a special case */
111 		if (remain <= 0)
112 			return 0;
113 		*p = '0';
114 		return 1;
115 	}
116 	/* form a backwards decimal ascii string in <s> */
117 	while (num > 0) {
118 		if (digits >= (int) sizeof(s))
119 			return 0;
120 		s[digits++] = (num % 10) + '0';
121 		num = num / 10;
122 	}
123 	if (remain < digits) {
124 		/* not enough room left at <p> to hold number, so fill with
125 		 * '?' */
126 		for (i = 0; i < remain; i++, p++)
127 			*p = '?';
128 		return remain;
129 	}
130 	/* plug in the decimal ascii string representing the number, by */
131 	/* reversing the string we just built in <s> */
132 	i = digits;
133 	while (i > 0) {
134 		i--;
135 		*p = s[i];
136 		p++;
137 	}
138 	return digits;
139 }
140 
141 /* Reads <devInfo>, and converts its contents to a printable string at <p>,
142  * writing at most <remain> bytes.  Note there is NO '\0' termination
143  * written to <p>.
144  *
145  * Pass <devix> >= 0 if you want a device index presented.
146  *
147  * Returns the number of bytes written to <p>.
148  */
149 static inline int
vbuschannel_devinfo_to_string(ULTRA_VBUS_DEVICEINFO * devinfo,char * p,int remain,int devix)150 vbuschannel_devinfo_to_string(ULTRA_VBUS_DEVICEINFO *devinfo,
151 				  char *p, int remain, int devix)
152 {
153 	char *psrc;
154 	int nsrc, x, i, pad;
155 	int chars = 0;
156 
157 	psrc = &(devinfo->devType[0]);
158 	nsrc = sizeof(devinfo->devType);
159 	if (vbuschannel_sanitize_buffer(NULL, 0, psrc, nsrc) <= 0)
160 		return 0;
161 
162 	/* emit device index */
163 	if (devix >= 0) {
164 		VBUSCHANNEL_ADDACHAR('[', p, remain, chars);
165 		x = vbuschannel_itoa(p, remain, devix);
166 		p += x;
167 		remain -= x;
168 		chars += x;
169 		VBUSCHANNEL_ADDACHAR(']', p, remain, chars);
170 	} else {
171 		VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
172 		VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
173 		VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
174 	}
175 
176 	/* emit device type */
177 	x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
178 	p += x;
179 	remain -= x;
180 	chars += x;
181 	pad = 15 - x;		/* pad device type to be exactly 15 chars */
182 	for (i = 0; i < pad; i++)
183 		VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
184 	VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
185 
186 	/* emit driver name */
187 	psrc = &(devinfo->drvName[0]);
188 	nsrc = sizeof(devinfo->drvName);
189 	x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
190 	p += x;
191 	remain -= x;
192 	chars += x;
193 	pad = 15 - x;		/* pad driver name to be exactly 15 chars */
194 	for (i = 0; i < pad; i++)
195 		VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
196 	VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
197 
198 	/* emit strings */
199 	psrc = &(devinfo->infoStrings[0]);
200 	nsrc = sizeof(devinfo->infoStrings);
201 	x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
202 	p += x;
203 	remain -= x;
204 	chars += x;
205 	VBUSCHANNEL_ADDACHAR('\n', p, remain, chars);
206 
207 	return chars;
208 }
209 
210 #endif
211