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