1 66660095SIan Lepore /*-
2 66660095SIan Lepore * SPDX-License-Identifier: BSD-2-Clause
3 66660095SIan Lepore *
4 66660095SIan Lepore * Copyright (c) 2018 S.F.T. Inc.
5 66660095SIan Lepore *
6 66660095SIan Lepore * Redistribution and use in source and binary forms, with or without
7 66660095SIan Lepore * modification, are permitted provided that the following conditions
8 66660095SIan Lepore * are met:
9 66660095SIan Lepore * 1. Redistributions of source code must retain the above copyright
10 66660095SIan Lepore * notice, this list of conditions and the following disclaimer.
11 66660095SIan Lepore * 2. Redistributions in binary form must reproduce the above copyright
12 66660095SIan Lepore * notice, this list of conditions and the following disclaimer in the
13 66660095SIan Lepore * documentation and/or other materials provided with the distribution.
14 66660095SIan Lepore *
15 66660095SIan Lepore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 66660095SIan Lepore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 66660095SIan Lepore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 66660095SIan Lepore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 66660095SIan Lepore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 66660095SIan Lepore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 66660095SIan Lepore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 66660095SIan Lepore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 66660095SIan Lepore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 66660095SIan Lepore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 66660095SIan Lepore * SUCH DAMAGE.
26 66660095SIan Lepore */
27 66660095SIan Lepore
28 66660095SIan Lepore #include <sys/types.h>
29 66660095SIan Lepore #include <sys/ioccom.h>
30 66660095SIan Lepore #include <sys/spigenio.h>
31 66660095SIan Lepore #include <sys/sysctl.h>
32 66660095SIan Lepore
33 66660095SIan Lepore #include <errno.h>
34 66660095SIan Lepore #include <fcntl.h>
35 66660095SIan Lepore #include <inttypes.h>
36 66660095SIan Lepore #include <limits.h>
37 66660095SIan Lepore #include <memory.h>
38 66660095SIan Lepore #include <stdio.h>
39 66660095SIan Lepore #include <stdlib.h>
40 66660095SIan Lepore #include <string.h>
41 66660095SIan Lepore #include <string.h>
42 66660095SIan Lepore #include <unistd.h>
43 66660095SIan Lepore
44 66660095SIan Lepore #define DEFAULT_DEVICE_NAME "/dev/spigen0.0"
45 66660095SIan Lepore
46 66660095SIan Lepore #define DEFAULT_BUFFER_SIZE 8192
47 66660095SIan Lepore
48 66660095SIan Lepore #define DIR_READ 0
49 66660095SIan Lepore #define DIR_WRITE 1
50 66660095SIan Lepore #define DIR_READWRITE 2
51 66660095SIan Lepore #define DIR_NONE -1
52 66660095SIan Lepore
53 66660095SIan Lepore struct spi_options {
54 66660095SIan Lepore int mode; /* mode (0,1,2,3, -1 == use default) */
55 66660095SIan Lepore int speed; /* speed (in Hz, -1 == use default) */
56 66660095SIan Lepore int count; /* count (0 through 'n' bytes, negative for
57 66660095SIan Lepore * stdin length) */
58 66660095SIan Lepore int binary; /* non-zero for binary output or zero for
59 66660095SIan Lepore * ASCII output when ASCII != 0 */
60 66660095SIan Lepore int ASCII; /* zero for binary input and output.
61 66660095SIan Lepore * non-zero for ASCII input, 'binary'
62 66660095SIan Lepore * determines output */
63 66660095SIan Lepore int lsb; /* non-zero for LSB order (default order is
64 66660095SIan Lepore * MSB) */
65 66660095SIan Lepore int verbose; /* non-zero for verbosity */
66 66660095SIan Lepore int ncmd; /* bytes to skip for incoming data */
67 66660095SIan Lepore uint8_t *pcmd; /* command data (NULL if none) */
68 66660095SIan Lepore };
69 66660095SIan Lepore
70 66660095SIan Lepore static void usage(void);
71 66660095SIan Lepore static int interpret_command_bytes(const char *parg, struct spi_options *popt);
72 66660095SIan Lepore static void * prep_write_buffer(struct spi_options *popt);
73 66660095SIan Lepore static int _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb);
74 66660095SIan Lepore static int _do_data_output(void *pr, struct spi_options *popt);
75 66660095SIan Lepore static int get_info(int hdev, const char *dev_name);
76 66660095SIan Lepore static int set_mode(int hdev, struct spi_options *popt);
77 66660095SIan Lepore static int set_speed(int hdev, struct spi_options *popt);
78 66660095SIan Lepore static int hexval(char c);
79 66660095SIan Lepore static int perform_read(int hdev, struct spi_options *popt);
80 66660095SIan Lepore static int perform_write(int hdev, struct spi_options *popt);
81 66660095SIan Lepore static int perform_readwrite(int hdev, struct spi_options *popt);
82 66660095SIan Lepore static void verbose_dump_buffer(void *pbuf, int icount, int lsb);
83 66660095SIan Lepore
84 66660095SIan Lepore /*
85 66660095SIan Lepore * LSB array - reversebits[n] is the LSB value of n as an MSB. Use this array
86 66660095SIan Lepore * to obtain a reversed bit pattern of the index value when bits must
87 66660095SIan Lepore * be sent/received in an LSB order vs the default MSB
88 66660095SIan Lepore */
89 66660095SIan Lepore static uint8_t reversebits[256] = {
90 66660095SIan Lepore 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
91 66660095SIan Lepore 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
92 66660095SIan Lepore 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
93 66660095SIan Lepore 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
94 66660095SIan Lepore 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
95 66660095SIan Lepore 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
96 66660095SIan Lepore 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
97 66660095SIan Lepore 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
98 66660095SIan Lepore 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
99 66660095SIan Lepore 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
100 66660095SIan Lepore 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
101 66660095SIan Lepore 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
102 66660095SIan Lepore 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
103 66660095SIan Lepore 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
104 66660095SIan Lepore 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
105 66660095SIan Lepore 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
106 66660095SIan Lepore 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
107 66660095SIan Lepore 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
108 66660095SIan Lepore 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
109 66660095SIan Lepore 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
110 66660095SIan Lepore 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
111 66660095SIan Lepore 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
112 66660095SIan Lepore 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
113 66660095SIan Lepore 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
114 66660095SIan Lepore 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
115 66660095SIan Lepore 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
116 66660095SIan Lepore 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
117 66660095SIan Lepore 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
118 66660095SIan Lepore 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
119 66660095SIan Lepore 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
120 66660095SIan Lepore 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
121 66660095SIan Lepore 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
122 66660095SIan Lepore };
123 66660095SIan Lepore
124 66660095SIan Lepore
125 66660095SIan Lepore static void
usage(void)126 66660095SIan Lepore usage(void)
127 66660095SIan Lepore {
128 66660095SIan Lepore fputs(getprogname(), stderr);
129 66660095SIan Lepore fputs(" - communicate on SPI bus with slave devices\n"
130 66660095SIan Lepore "Usage:\n"
131 66660095SIan Lepore " spi [-f device] [-d r|w|rw] [-m mode] [-s max-speed] [-c count]\n"
132 66660095SIan Lepore " [-C \"command bytes\"] [-A] [-b] [-L] [-v]\n"
133 66660095SIan Lepore " spi -i [-f device] [-v]\n"
134 66660095SIan Lepore " spi -h\n"
135 66660095SIan Lepore " where\n"
136 66660095SIan Lepore " -f specifies the device (default is spigen0.0)\n"
137 66660095SIan Lepore " -d specifies the operation (r, w, or rw; default is rw)\n"
138 66660095SIan Lepore " -m specifies the mode (0, 1, 2, or 3)\n"
139 66660095SIan Lepore " -s specifies the maximum speed (default is 0, device default)\n"
140 66660095SIan Lepore " -c specifies the number of data bytes to transfer (default 0, i.e. none)\n"
141 66660095SIan Lepore " A negative value uses the length of the input data\n"
142 66660095SIan Lepore " -C specifies 'command bytes' to be sent, as 2 byte hexadecimal values\n"
143 66660095SIan Lepore " (these should be quoted, separated by optional white space)\n"
144 66660095SIan Lepore " -L specifies 'LSB' order on the SPI bus (default is MSB)\n"
145 66660095SIan Lepore " -i query information about the device\n"
146 66660095SIan Lepore " -A uses ASCII for input/output as 2-digit hex values\n"
147 66660095SIan Lepore " -b Override output format as binary (only valid with '-A')\n"
148 66660095SIan Lepore " -v verbose output\n"
149 66660095SIan Lepore " -h prints this message\n"
150 66660095SIan Lepore "\n"
151 66660095SIan Lepore "NOTE: setting the mode and/or speed is 'sticky'. Subsequent transactions\n"
152 66660095SIan Lepore " on that device will, by default, use the previously set values.\n"
153 66660095SIan Lepore "\n",
154 66660095SIan Lepore stderr);
155 66660095SIan Lepore }
156 66660095SIan Lepore
157 66660095SIan Lepore int
main(int argc,char * argv[],char * envp[]__unused)158 66660095SIan Lepore main(int argc, char *argv[], char *envp[] __unused)
159 66660095SIan Lepore {
160 66660095SIan Lepore struct spi_options opt;
161 66660095SIan Lepore int err, ch, hdev, finfo, fdir;
162 66660095SIan Lepore char *pstr;
163 66660095SIan Lepore char dev_name[PATH_MAX * 2 + 5];
164 66660095SIan Lepore
165 66660095SIan Lepore finfo = 0;
166 66660095SIan Lepore fdir = DIR_NONE;
167 66660095SIan Lepore
168 66660095SIan Lepore hdev = -1;
169 66660095SIan Lepore err = 0;
170 66660095SIan Lepore
171 66660095SIan Lepore dev_name[0] = 0;
172 66660095SIan Lepore
173 66660095SIan Lepore opt.mode = -1;
174 66660095SIan Lepore opt.speed = -1;
175 66660095SIan Lepore opt.count = 0;
176 66660095SIan Lepore opt.ASCII = 0;
177 66660095SIan Lepore opt.binary = 0;
178 66660095SIan Lepore opt.lsb = 0;
179 66660095SIan Lepore opt.verbose = 0;
180 66660095SIan Lepore opt.ncmd = 0;
181 66660095SIan Lepore opt.pcmd = NULL;
182 66660095SIan Lepore
183 66660095SIan Lepore while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLvih")) != -1) {
184 66660095SIan Lepore switch (ch) {
185 66660095SIan Lepore case 'd':
186 66660095SIan Lepore if (optarg[0] == 'r') {
187 66660095SIan Lepore if (optarg[1] == 'w' && optarg[2] == 0) {
188 66660095SIan Lepore fdir = DIR_READWRITE;
189 66660095SIan Lepore }
190 66660095SIan Lepore else if (optarg[1] == 0) {
191 66660095SIan Lepore fdir = DIR_READ;
192 66660095SIan Lepore }
193 66660095SIan Lepore }
194 66660095SIan Lepore else if (optarg[0] == 'w' && optarg[1] == 0) {
195 66660095SIan Lepore fdir = DIR_WRITE;
196 66660095SIan Lepore }
197 66660095SIan Lepore else {
198 66660095SIan Lepore err = 1;
199 66660095SIan Lepore }
200 66660095SIan Lepore break;
201 66660095SIan Lepore
202 66660095SIan Lepore case 'f':
203 66660095SIan Lepore if (!optarg[0]) { /* unlikely */
204 66660095SIan Lepore fputs("error - missing device name\n", stderr);
205 66660095SIan Lepore err = 1;
206 66660095SIan Lepore }
207 66660095SIan Lepore else {
208 66660095SIan Lepore if (optarg[0] == '/')
209 66660095SIan Lepore strlcpy(dev_name, optarg,
210 66660095SIan Lepore sizeof(dev_name));
211 66660095SIan Lepore else
212 66660095SIan Lepore snprintf(dev_name, sizeof(dev_name),
213 66660095SIan Lepore "/dev/%s", optarg);
214 66660095SIan Lepore }
215 66660095SIan Lepore break;
216 66660095SIan Lepore
217 66660095SIan Lepore case 'm':
218 66660095SIan Lepore opt.mode = (int)strtol(optarg, &pstr, 10);
219 66660095SIan Lepore
220 66660095SIan Lepore if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) {
221 66660095SIan Lepore fprintf(stderr, "Invalid mode specified: %s\n",
222 66660095SIan Lepore optarg);
223 66660095SIan Lepore err = 1;
224 66660095SIan Lepore }
225 66660095SIan Lepore break;
226 66660095SIan Lepore
227 66660095SIan Lepore case 's':
228 66660095SIan Lepore opt.speed = (int)strtol(optarg, &pstr, 10);
229 66660095SIan Lepore
230 66660095SIan Lepore if (!pstr || *pstr || opt.speed < 0) {
231 66660095SIan Lepore fprintf(stderr, "Invalid speed specified: %s\n",
232 66660095SIan Lepore optarg);
233 66660095SIan Lepore err = 1;
234 66660095SIan Lepore }
235 66660095SIan Lepore break;
236 66660095SIan Lepore
237 66660095SIan Lepore case 'c':
238 66660095SIan Lepore opt.count = (int)strtol(optarg, &pstr, 10);
239 66660095SIan Lepore
240 66660095SIan Lepore if (!pstr || *pstr) {
241 66660095SIan Lepore fprintf(stderr, "Invalid count specified: %s\n",
242 66660095SIan Lepore optarg);
243 66660095SIan Lepore err = 1;
244 66660095SIan Lepore }
245 66660095SIan Lepore break;
246 66660095SIan Lepore
247 66660095SIan Lepore case 'C':
248 66660095SIan Lepore if(opt.pcmd) /* specified more than once */
249 66660095SIan Lepore err = 1;
250 66660095SIan Lepore else {
251 66660095SIan Lepore /* get malloc'd buffer or error */
252 66660095SIan Lepore if (interpret_command_bytes(optarg, &opt))
253 66660095SIan Lepore err = 1;
254 66660095SIan Lepore }
255 66660095SIan Lepore
256 66660095SIan Lepore break;
257 66660095SIan Lepore
258 66660095SIan Lepore case 'A':
259 66660095SIan Lepore opt.ASCII = 1;
260 66660095SIan Lepore break;
261 66660095SIan Lepore
262 66660095SIan Lepore case 'b':
263 66660095SIan Lepore opt.binary = 1;
264 66660095SIan Lepore break;
265 66660095SIan Lepore
266 66660095SIan Lepore case 'L':
267 66660095SIan Lepore opt.lsb = 1;
268 66660095SIan Lepore break;
269 66660095SIan Lepore
270 66660095SIan Lepore case 'v':
271 66660095SIan Lepore opt.verbose++;
272 66660095SIan Lepore break;
273 66660095SIan Lepore
274 66660095SIan Lepore case 'i':
275 66660095SIan Lepore finfo = 1;
276 66660095SIan Lepore break;
277 66660095SIan Lepore
278 66660095SIan Lepore default:
279 66660095SIan Lepore err = 1;
280 66660095SIan Lepore /* FALLTHROUGH */
281 66660095SIan Lepore case 'h':
282 66660095SIan Lepore usage();
283 66660095SIan Lepore goto the_end;
284 66660095SIan Lepore }
285 66660095SIan Lepore }
286 66660095SIan Lepore
287 66660095SIan Lepore argc -= optind;
288 66660095SIan Lepore argv += optind;
289 66660095SIan Lepore
290 66660095SIan Lepore if (err ||
291 66660095SIan Lepore (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
292 66660095SIan Lepore /*
293 66660095SIan Lepore * if any of the direction, mode, speed, or count not specified,
294 66660095SIan Lepore * print usage
295 66660095SIan Lepore */
296 66660095SIan Lepore
297 66660095SIan Lepore usage();
298 66660095SIan Lepore goto the_end;
299 66660095SIan Lepore }
300 66660095SIan Lepore
301 66660095SIan Lepore if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) {
302 66660095SIan Lepore /*
303 66660095SIan Lepore * count was specified, but direction was not. default is
304 66660095SIan Lepore * read/write
305 66660095SIan Lepore */
306 66660095SIan Lepore /*
307 66660095SIan Lepore * this includes a negative count, which implies write from
308 66660095SIan Lepore * stdin
309 66660095SIan Lepore */
310 66660095SIan Lepore if (opt.count == 0)
311 66660095SIan Lepore fdir = DIR_WRITE;
312 66660095SIan Lepore else
313 66660095SIan Lepore fdir = DIR_READWRITE;
314 66660095SIan Lepore }
315 66660095SIan Lepore
316 66660095SIan Lepore if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) {
317 66660095SIan Lepore fprintf(stderr, "Invalid length %d when not writing data\n",
318 66660095SIan Lepore opt.count);
319 66660095SIan Lepore
320 66660095SIan Lepore err = 1;
321 66660095SIan Lepore usage();
322 66660095SIan Lepore goto the_end;
323 66660095SIan Lepore }
324 66660095SIan Lepore
325 66660095SIan Lepore
326 66660095SIan Lepore if (!dev_name[0]) /* no device name specified */
327 66660095SIan Lepore strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name));
328 66660095SIan Lepore
329 66660095SIan Lepore hdev = open(dev_name, O_RDWR);
330 66660095SIan Lepore
331 66660095SIan Lepore if (hdev == -1) {
332 66660095SIan Lepore fprintf(stderr, "Error - unable to open '%s', errno=%d\n",
333 66660095SIan Lepore dev_name, errno);
334 66660095SIan Lepore err = 1;
335 66660095SIan Lepore goto the_end;
336 66660095SIan Lepore }
337 66660095SIan Lepore
338 66660095SIan Lepore if (finfo) {
339 66660095SIan Lepore err = get_info(hdev, dev_name);
340 66660095SIan Lepore goto the_end;
341 66660095SIan Lepore }
342 66660095SIan Lepore
343 66660095SIan Lepore /* check and assign mode, speed */
344 66660095SIan Lepore
345 66660095SIan Lepore if (opt.mode != -1) {
346 66660095SIan Lepore err = set_mode(hdev, &opt);
347 66660095SIan Lepore
348 66660095SIan Lepore if (err)
349 66660095SIan Lepore goto the_end;
350 66660095SIan Lepore }
351 66660095SIan Lepore
352 66660095SIan Lepore if (opt.speed != -1) {
353 66660095SIan Lepore err = set_speed(hdev, &opt);
354 66660095SIan Lepore
355 66660095SIan Lepore if (err)
356 66660095SIan Lepore goto the_end;
357 66660095SIan Lepore }
358 66660095SIan Lepore
359 66660095SIan Lepore /* do data transfer */
360 66660095SIan Lepore
361 66660095SIan Lepore if (fdir == DIR_READ) {
362 66660095SIan Lepore err = perform_read(hdev, &opt);
363 66660095SIan Lepore }
364 66660095SIan Lepore else if (fdir == DIR_WRITE) {
365 66660095SIan Lepore err = perform_write(hdev, &opt);
366 66660095SIan Lepore }
367 66660095SIan Lepore else if (fdir == DIR_READWRITE) {
368 66660095SIan Lepore err = perform_readwrite(hdev, &opt);
369 66660095SIan Lepore }
370 66660095SIan Lepore
371 66660095SIan Lepore the_end:
372 66660095SIan Lepore
373 66660095SIan Lepore if (hdev != -1)
374 66660095SIan Lepore close(hdev);
375 66660095SIan Lepore
376 66660095SIan Lepore free(opt.pcmd);
377 66660095SIan Lepore
378 66660095SIan Lepore return (err);
379 66660095SIan Lepore }
380 66660095SIan Lepore
381 66660095SIan Lepore static int
interpret_command_bytes(const char * parg,struct spi_options * popt)382 66660095SIan Lepore interpret_command_bytes(const char *parg, struct spi_options *popt)
383 66660095SIan Lepore {
384 66660095SIan Lepore int ch, ch2, ctr, cbcmd, err;
385 66660095SIan Lepore const char *ppos;
386 66660095SIan Lepore void *ptemp;
387 66660095SIan Lepore uint8_t *pcur;
388 66660095SIan Lepore
389 66660095SIan Lepore err = 0;
390 66660095SIan Lepore cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */
391 66660095SIan Lepore popt->pcmd = (uint8_t *)malloc(cbcmd);
392 66660095SIan Lepore
393 66660095SIan Lepore if (!popt->pcmd)
394 66660095SIan Lepore return 1;
395 66660095SIan Lepore
396 66660095SIan Lepore pcur = popt->pcmd;
397 66660095SIan Lepore
398 66660095SIan Lepore ctr = 0;
399 66660095SIan Lepore ppos = parg;
400 66660095SIan Lepore
401 66660095SIan Lepore while (*ppos) {
402 66660095SIan Lepore while (*ppos && *ppos <= ' ') {
403 66660095SIan Lepore ppos++; /* skip (optional) leading white space */
404 66660095SIan Lepore }
405 66660095SIan Lepore
406 66660095SIan Lepore if (!*ppos)
407 66660095SIan Lepore break; /* I am done */
408 66660095SIan Lepore
409 66660095SIan Lepore ch = hexval(*(ppos++));
410 66660095SIan Lepore if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */
411 66660095SIan Lepore err = 1;
412 66660095SIan Lepore goto the_end;
413 66660095SIan Lepore }
414 66660095SIan Lepore
415 66660095SIan Lepore ch2 = hexval(*(ppos++));
416 66660095SIan Lepore if (ch2 < 0) {
417 66660095SIan Lepore err = 1;
418 66660095SIan Lepore goto the_end;
419 66660095SIan Lepore }
420 66660095SIan Lepore
421 66660095SIan Lepore ch = (ch * 16 + ch2) & 0xff; /* convert to byte */
422 66660095SIan Lepore
423 66660095SIan Lepore if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */
424 66660095SIan Lepore cbcmd += 8192; /* increase by additional 8k */
425 66660095SIan Lepore ptemp = realloc(popt->pcmd, cbcmd);
426 66660095SIan Lepore
427 66660095SIan Lepore if (!ptemp) {
428 66660095SIan Lepore err = 1;
429 66660095SIan Lepore fprintf(stderr,
430 66660095SIan Lepore "Not enough memory to interpret command bytes, errno=%d\n",
431 66660095SIan Lepore errno);
432 66660095SIan Lepore goto the_end;
433 66660095SIan Lepore }
434 66660095SIan Lepore
435 66660095SIan Lepore popt->pcmd = (uint8_t *)ptemp;
436 66660095SIan Lepore pcur = popt->pcmd + ctr;
437 66660095SIan Lepore }
438 66660095SIan Lepore
439 66660095SIan Lepore if (popt->lsb)
440 66660095SIan Lepore *pcur = reversebits[ch];
441 66660095SIan Lepore else
442 66660095SIan Lepore *pcur = (uint8_t)ch;
443 66660095SIan Lepore
444 66660095SIan Lepore pcur++;
445 66660095SIan Lepore ctr++;
446 66660095SIan Lepore }
447 66660095SIan Lepore
448 66660095SIan Lepore popt->ncmd = ctr; /* record num bytes in '-C' argument */
449 66660095SIan Lepore
450 66660095SIan Lepore the_end:
451 66660095SIan Lepore
452 66660095SIan Lepore /* at this point popt->pcmd is NULL or a valid pointer */
453 66660095SIan Lepore
454 66660095SIan Lepore return err;
455 66660095SIan Lepore }
456 66660095SIan Lepore
457 66660095SIan Lepore static int
get_info(int hdev,const char * dev_name)458 66660095SIan Lepore get_info(int hdev, const char *dev_name)
459 66660095SIan Lepore {
460 66660095SIan Lepore uint32_t fmode, fspeed;
461 66660095SIan Lepore int err;
462 66660095SIan Lepore char temp_buf[PATH_MAX], cpath[PATH_MAX];
463 66660095SIan Lepore
464 66660095SIan Lepore if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */
465 66660095SIan Lepore strlcpy(cpath, temp_buf, sizeof(cpath)); /* this shouldn't happen */
466 66660095SIan Lepore
467 66660095SIan Lepore err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode);
468 66660095SIan Lepore
469 66660095SIan Lepore if (err == 0)
470 66660095SIan Lepore err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed);
471 66660095SIan Lepore
472 66660095SIan Lepore if (err == 0) {
473 66660095SIan Lepore fprintf(stderr,
474 66660095SIan Lepore "Device name: %s\n"
475 66660095SIan Lepore "Device mode: %d\n"
476 66660095SIan Lepore "Device speed: %d\n",
477 66660095SIan Lepore cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf);
478 66660095SIan Lepore }
479 66660095SIan Lepore else
480 66660095SIan Lepore fprintf(stderr, "Unable to query info (err=%d), errno=%d\n",
481 66660095SIan Lepore err, errno);
482 66660095SIan Lepore
483 66660095SIan Lepore return err;
484 66660095SIan Lepore }
485 66660095SIan Lepore
486 66660095SIan Lepore static int
set_mode(int hdev,struct spi_options * popt)487 66660095SIan Lepore set_mode(int hdev, struct spi_options *popt)
488 66660095SIan Lepore {
489 66660095SIan Lepore uint32_t fmode = popt->mode;
490 66660095SIan Lepore
491 66660095SIan Lepore if (popt->mode < 0) /* use default? */
492 66660095SIan Lepore return 0;
493 66660095SIan Lepore
494 66660095SIan Lepore return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode);
495 66660095SIan Lepore }
496 66660095SIan Lepore
497 66660095SIan Lepore static int
set_speed(int hdev,struct spi_options * popt)498 66660095SIan Lepore set_speed(int hdev, struct spi_options *popt)
499 66660095SIan Lepore {
500 66660095SIan Lepore uint32_t clock_speed = popt->speed;
501 66660095SIan Lepore
502 66660095SIan Lepore if (popt->speed < 0)
503 66660095SIan Lepore return 0;
504 66660095SIan Lepore
505 66660095SIan Lepore return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed);
506 66660095SIan Lepore }
507 66660095SIan Lepore
508 66660095SIan Lepore static int
hexval(char c)509 66660095SIan Lepore hexval(char c)
510 66660095SIan Lepore {
511 66660095SIan Lepore if (c >= '0' && c <= '9') {
512 66660095SIan Lepore return c - '0';
513 66660095SIan Lepore } else if (c >= 'A' && c <= 'F') {
514 66660095SIan Lepore return c - 'A' + 10;
515 66660095SIan Lepore } else if (c >= 'a' && c <= 'f') {
516 66660095SIan Lepore return c - 'a' + 10;
517 66660095SIan Lepore }
518 66660095SIan Lepore return -1;
519 66660095SIan Lepore }
520 66660095SIan Lepore
521 66660095SIan Lepore static void *
prep_write_buffer(struct spi_options * popt)522 66660095SIan Lepore prep_write_buffer(struct spi_options *popt)
523 66660095SIan Lepore {
524 66660095SIan Lepore int ch, ch2, ch3, ncmd, lsb, err;
525 66660095SIan Lepore uint8_t *pdata, *pdat2;
526 66660095SIan Lepore size_t cbdata, cbread;
527 66660095SIan Lepore const char *szbytes;
528 66660095SIan Lepore
529 66660095SIan Lepore ncmd = popt->ncmd; /* num command bytes (can be zero) */
530 66660095SIan Lepore
531 66660095SIan Lepore if (ncmd == 0 && popt->count == 0)
532 66660095SIan Lepore return NULL; /* always since it's an error if it happens
533 66660095SIan Lepore * now */
534 66660095SIan Lepore
535 66660095SIan Lepore if (popt->count < 0) {
536 66660095SIan Lepore cbdata = DEFAULT_BUFFER_SIZE;
537 66660095SIan Lepore }
538 66660095SIan Lepore else {
539 66660095SIan Lepore cbdata = popt->count;
540 66660095SIan Lepore }
541 66660095SIan Lepore
542 66660095SIan Lepore lsb = popt->lsb; /* non-zero if LSB order; else MSB */
543 66660095SIan Lepore
544 66660095SIan Lepore pdata = malloc(cbdata + ncmd + 1);
545 66660095SIan Lepore cbread = 0;
546 66660095SIan Lepore
547 66660095SIan Lepore err = 0;
548 66660095SIan Lepore
549 66660095SIan Lepore if (!pdata)
550 66660095SIan Lepore return NULL;
551 66660095SIan Lepore
552 66660095SIan Lepore if (popt->pcmd && ncmd > 0) {
553 66660095SIan Lepore memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */
554 66660095SIan Lepore pdat2 = pdata + ncmd;
555 66660095SIan Lepore }
556 66660095SIan Lepore else
557 66660095SIan Lepore pdat2 = pdata; /* no prepended command data */
558 66660095SIan Lepore
559 66660095SIan Lepore /*
560 66660095SIan Lepore * read up to 'cbdata' bytes. If I get an EOF, do one of two things:
561 66660095SIan Lepore * a) change the data count to match how many bytes I read in b) fill
562 66660095SIan Lepore * the rest of the input buffer with zeros
563 66660095SIan Lepore *
564 66660095SIan Lepore * If the specified length is negative, I do 'a', else 'b'
565 66660095SIan Lepore */
566 66660095SIan Lepore
567 66660095SIan Lepore while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) {
568 66660095SIan Lepore if (popt->ASCII) {
569 66660095SIan Lepore /* skip consecutive white space */
570 66660095SIan Lepore
571 66660095SIan Lepore while (ch <= ' ') {
572 66660095SIan Lepore if ((ch = fgetc(stdin)) == EOF)
573 66660095SIan Lepore break;
574 66660095SIan Lepore }
575 66660095SIan Lepore
576 66660095SIan Lepore if (ch != EOF) {
577 66660095SIan Lepore ch2 = hexval(ch);
578 66660095SIan Lepore
579 66660095SIan Lepore if (ch2 < 0) {
580 66660095SIan Lepore invalid_character:
581 66660095SIan Lepore fprintf(stderr,
582 66660095SIan Lepore "Invalid input character '%c'\n", ch);
583 66660095SIan Lepore err = 1;
584 66660095SIan Lepore break;
585 66660095SIan Lepore }
586 66660095SIan Lepore
587 66660095SIan Lepore ch = fgetc(stdin);
588 66660095SIan Lepore
589 66660095SIan Lepore if (ch != EOF) {
590 66660095SIan Lepore ch3 = hexval(ch);
591 66660095SIan Lepore
592 66660095SIan Lepore if (ch3 < 0)
593 66660095SIan Lepore goto invalid_character;
594 66660095SIan Lepore
595 66660095SIan Lepore ch = ch2 * 16 + ch3;
596 66660095SIan Lepore }
597 66660095SIan Lepore }
598 66660095SIan Lepore
599 66660095SIan Lepore if (err || ch == EOF)
600 66660095SIan Lepore break;
601 66660095SIan Lepore }
602 66660095SIan Lepore
603 66660095SIan Lepore /* for LSB, flip the bits - otherwise, just copy the value */
604 66660095SIan Lepore if (lsb)
605 66660095SIan Lepore pdat2[cbread] = reversebits[ch];
606 66660095SIan Lepore else
607 66660095SIan Lepore pdat2[cbread] = (uint8_t) ch;
608 66660095SIan Lepore
609 66660095SIan Lepore cbread++; /* increment num bytes read so far */
610 66660095SIan Lepore }
611 66660095SIan Lepore
612 66660095SIan Lepore /* if it was an error, not an EOF, that ended the I/O, return NULL */
613 66660095SIan Lepore
614 66660095SIan Lepore if (err || ferror(stdin)) {
615 66660095SIan Lepore free(pdata);
616 66660095SIan Lepore return NULL;
617 66660095SIan Lepore }
618 66660095SIan Lepore
619 66660095SIan Lepore if (popt->verbose > 0) {
620 66660095SIan Lepore const char *sz_bytes;
621 66660095SIan Lepore
622 66660095SIan Lepore if (cbread != 1)
623 66660095SIan Lepore sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
624 66660095SIan Lepore else
625 66660095SIan Lepore sz_bytes = "byte";
626 66660095SIan Lepore
627 66660095SIan Lepore if (popt->ASCII)
628 66660095SIan Lepore fprintf(stderr, "ASCII input of %zd %s\n", cbread,
629 66660095SIan Lepore sz_bytes);
630 66660095SIan Lepore else
631 66660095SIan Lepore fprintf(stderr, "Binary input of %zd %s\n", cbread,
632 66660095SIan Lepore sz_bytes);
633 66660095SIan Lepore }
634 66660095SIan Lepore
635 66660095SIan Lepore /*
636 66660095SIan Lepore * if opt.count is negative, copy actual byte count to opt.count which does
637 66660095SIan Lepore * not include any of the 'command' bytes that are being sent. Can be zero.
638 66660095SIan Lepore */
639 66660095SIan Lepore if (popt->count < 0) {
640 66660095SIan Lepore popt->count = cbread;
641 66660095SIan Lepore }
642 66660095SIan Lepore /*
643 66660095SIan Lepore * for everything else, fill the rest of the read buffer with '0'
644 66660095SIan Lepore * bytes, as per the standard practice for SPI
645 66660095SIan Lepore */
646 66660095SIan Lepore else {
647 66660095SIan Lepore while (cbread < cbdata)
648 66660095SIan Lepore pdat2[cbread++] = 0;
649 66660095SIan Lepore }
650 66660095SIan Lepore
651 66660095SIan Lepore /*
652 66660095SIan Lepore * popt->count bytes will be sent and read from the SPI, preceded by the
653 66660095SIan Lepore * 'popt->ncmd' command bytes (if any).
654 66660095SIan Lepore * So we must use 'popt->count' and 'popt->ncmd' from this point on in
655 66660095SIan Lepore * the code.
656 66660095SIan Lepore */
657 66660095SIan Lepore
658 66660095SIan Lepore if (popt->verbose > 0 && popt->count + popt->ncmd) {
659 66660095SIan Lepore if ((popt->count + popt->ncmd) == 1)
660 66660095SIan Lepore szbytes = "byte";
661 66660095SIan Lepore else
662 66660095SIan Lepore szbytes = "bytes";
663 66660095SIan Lepore
664 66660095SIan Lepore fprintf(stderr, "Writing %d %s to SPI device\n",
665 66660095SIan Lepore popt->count + popt->ncmd, szbytes);
666 66660095SIan Lepore
667 66660095SIan Lepore verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb);
668 66660095SIan Lepore }
669 66660095SIan Lepore
670 66660095SIan Lepore return pdata;
671 66660095SIan Lepore }
672 66660095SIan Lepore
673 66660095SIan Lepore static int
_read_write(int hdev,void * bufw,void * bufr,int cbrw,int lsb)674 66660095SIan Lepore _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb)
675 66660095SIan Lepore {
676 66660095SIan Lepore int err, ctr;
677 66660095SIan Lepore struct spigen_transfer spi;
678 66660095SIan Lepore
679 66660095SIan Lepore if (!cbrw)
680 66660095SIan Lepore return 0;
681 66660095SIan Lepore
682 66660095SIan Lepore if (!bufr)
683 66660095SIan Lepore bufr = bufw;
684 66660095SIan Lepore else
685 66660095SIan Lepore memcpy(bufr, bufw, cbrw); /* transaction uses bufr for
686 66660095SIan Lepore * both R and W */
687 66660095SIan Lepore
688 66660095SIan Lepore bzero(&spi, sizeof(spi)); /* zero structure first */
689 66660095SIan Lepore
690 66660095SIan Lepore /* spigen code seems to suggest there must be at least 1 command byte */
691 66660095SIan Lepore
692 66660095SIan Lepore spi.st_command.iov_base = bufr;
693 66660095SIan Lepore spi.st_command.iov_len = cbrw;
694 66660095SIan Lepore
695 66660095SIan Lepore /*
696 66660095SIan Lepore * The remaining members for spi.st_data are zero - all bytes are
697 66660095SIan Lepore * 'command' for this. The driver doesn't really do anything different
698 66660095SIan Lepore * for 'command' vs 'data' and at least one command byte must be sent in
699 66660095SIan Lepore * the transaction.
700 66660095SIan Lepore */
701 66660095SIan Lepore
702 66660095SIan Lepore err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
703 66660095SIan Lepore
704 66660095SIan Lepore if (!err && lsb) {
705 66660095SIan Lepore /* flip the bits for 'lsb' mode */
706 66660095SIan Lepore for (ctr = 0; ctr < cbrw; ctr++) {
707 66660095SIan Lepore ((uint8_t *) bufr)[ctr] =
708 66660095SIan Lepore reversebits[((uint8_t *)bufr)[ctr]];
709 66660095SIan Lepore }
710 66660095SIan Lepore }
711 66660095SIan Lepore
712 66660095SIan Lepore if (err)
713 66660095SIan Lepore fprintf(stderr, "Error performing SPI transaction, errno=%d\n",
714 66660095SIan Lepore errno);
715 66660095SIan Lepore
716 66660095SIan Lepore return err;
717 66660095SIan Lepore }
718 66660095SIan Lepore
719 66660095SIan Lepore static int
_do_data_output(void * pr,struct spi_options * popt)720 66660095SIan Lepore _do_data_output(void *pr, struct spi_options *popt)
721 66660095SIan Lepore {
722 *917d1846SIan Lepore int err, idx, icount;
723 66660095SIan Lepore const char *sz_bytes, *sz_byte2;
724 66660095SIan Lepore const uint8_t *pbuf;
725 66660095SIan Lepore
726 66660095SIan Lepore pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */
727 66660095SIan Lepore icount = popt->count;
728 66660095SIan Lepore err = 0;
729 66660095SIan Lepore
730 66660095SIan Lepore if (icount <= 0) {
731 66660095SIan Lepore return -1; /* should not but could happen */
732 66660095SIan Lepore }
733 66660095SIan Lepore
734 66660095SIan Lepore if (icount != 1)
735 66660095SIan Lepore sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
736 66660095SIan Lepore else
737 66660095SIan Lepore sz_bytes = "byte";
738 66660095SIan Lepore
739 66660095SIan Lepore if (popt->ncmd != 1)
740 66660095SIan Lepore sz_byte2 = "bytes";
741 66660095SIan Lepore else
742 66660095SIan Lepore sz_byte2 = "byte";
743 66660095SIan Lepore
744 66660095SIan Lepore /* binary on stdout */
745 66660095SIan Lepore if (popt->binary || !popt->ASCII) {
746 66660095SIan Lepore if (popt->verbose > 0)
747 66660095SIan Lepore fprintf(stderr, "Binary output of %d %s\n", icount,
748 66660095SIan Lepore sz_bytes);
749 66660095SIan Lepore
750 66660095SIan Lepore err = (int)fwrite(pbuf, 1, icount, stdout) != icount;
751 66660095SIan Lepore }
752 66660095SIan Lepore else if (icount > 0) {
753 66660095SIan Lepore if (popt->verbose > 0)
754 66660095SIan Lepore fprintf(stderr, "ASCII output of %d %s\n", icount,
755 66660095SIan Lepore sz_bytes);
756 66660095SIan Lepore
757 66660095SIan Lepore /* ASCII output */
758 *917d1846SIan Lepore for (idx = 0; !err && idx < icount; idx++) {
759 *917d1846SIan Lepore if (idx) {
760 66660095SIan Lepore /*
761 66660095SIan Lepore * not the first time, insert separating space
762 66660095SIan Lepore */
763 66660095SIan Lepore err = fputc(' ', stdout) == EOF;
764 66660095SIan Lepore }
765 66660095SIan Lepore
766 66660095SIan Lepore if (!err)
767 *917d1846SIan Lepore err = fprintf(stdout, "%02hhx", pbuf[idx]) < 0;
768 66660095SIan Lepore }
769 66660095SIan Lepore
770 66660095SIan Lepore if (!err)
771 66660095SIan Lepore err = fputc('\n', stdout) == EOF;
772 66660095SIan Lepore }
773 66660095SIan Lepore
774 66660095SIan Lepore /* verbose text out on stderr */
775 66660095SIan Lepore
776 66660095SIan Lepore if (err)
777 66660095SIan Lepore fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
778 66660095SIan Lepore else if (popt->verbose > 0 && icount) {
779 66660095SIan Lepore fprintf(stderr,
780 66660095SIan Lepore "%d command %s and %d data %s read from SPI device\n",
781 66660095SIan Lepore popt->ncmd, sz_byte2, icount, sz_bytes);
782 66660095SIan Lepore
783 66660095SIan Lepore /* verbose output will show the command bytes as well */
784 66660095SIan Lepore verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb);
785 66660095SIan Lepore }
786 66660095SIan Lepore
787 66660095SIan Lepore return err;
788 66660095SIan Lepore }
789 66660095SIan Lepore
790 66660095SIan Lepore static int
perform_read(int hdev,struct spi_options * popt)791 66660095SIan Lepore perform_read(int hdev, struct spi_options *popt)
792 66660095SIan Lepore {
793 66660095SIan Lepore int icount, err;
794 66660095SIan Lepore void *pr, *pw;
795 66660095SIan Lepore
796 66660095SIan Lepore pr = NULL;
797 66660095SIan Lepore icount = popt->count + popt->ncmd;
798 66660095SIan Lepore
799 66660095SIan Lepore /* prep write buffer filled with 0 bytes */
800 66660095SIan Lepore pw = malloc(icount);
801 66660095SIan Lepore
802 66660095SIan Lepore if (!pw) {
803 66660095SIan Lepore err = -1;
804 66660095SIan Lepore goto the_end;
805 66660095SIan Lepore }
806 66660095SIan Lepore
807 66660095SIan Lepore bzero(pw, icount);
808 66660095SIan Lepore
809 66660095SIan Lepore /* if I included a command sequence, copy bytes to the write buf */
810 66660095SIan Lepore if (popt->pcmd && popt->ncmd > 0)
811 66660095SIan Lepore memcpy(pw, popt->pcmd, popt->ncmd);
812 66660095SIan Lepore
813 66660095SIan Lepore pr = malloc(icount + 1);
814 66660095SIan Lepore
815 66660095SIan Lepore if (!pr) {
816 66660095SIan Lepore err = -2;
817 66660095SIan Lepore goto the_end;
818 66660095SIan Lepore }
819 66660095SIan Lepore
820 66660095SIan Lepore bzero(pr, icount);
821 66660095SIan Lepore
822 66660095SIan Lepore err = _read_write(hdev, pw, pr, icount, popt->lsb);
823 66660095SIan Lepore
824 66660095SIan Lepore if (!err && popt->count > 0)
825 66660095SIan Lepore err = _do_data_output(pr, popt);
826 66660095SIan Lepore
827 66660095SIan Lepore the_end:
828 66660095SIan Lepore
829 66660095SIan Lepore free(pr);
830 66660095SIan Lepore free(pw);
831 66660095SIan Lepore
832 66660095SIan Lepore return err;
833 66660095SIan Lepore }
834 66660095SIan Lepore
835 66660095SIan Lepore static int
perform_write(int hdev,struct spi_options * popt)836 66660095SIan Lepore perform_write(int hdev, struct spi_options *popt)
837 66660095SIan Lepore {
838 66660095SIan Lepore int err;
839 66660095SIan Lepore void *pw;
840 66660095SIan Lepore
841 66660095SIan Lepore /* read data from cmd buf and stdin and write to 'write' buffer */
842 66660095SIan Lepore
843 66660095SIan Lepore pw = prep_write_buffer(popt);
844 66660095SIan Lepore
845 66660095SIan Lepore if (!pw) {
846 66660095SIan Lepore err = -1;
847 66660095SIan Lepore goto the_end;
848 66660095SIan Lepore }
849 66660095SIan Lepore
850 66660095SIan Lepore err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb);
851 66660095SIan Lepore
852 66660095SIan Lepore the_end:
853 66660095SIan Lepore
854 66660095SIan Lepore free(pw);
855 66660095SIan Lepore
856 66660095SIan Lepore return err;
857 66660095SIan Lepore }
858 66660095SIan Lepore
859 66660095SIan Lepore static int
perform_readwrite(int hdev,struct spi_options * popt)860 66660095SIan Lepore perform_readwrite(int hdev, struct spi_options *popt)
861 66660095SIan Lepore {
862 66660095SIan Lepore int icount, err;
863 66660095SIan Lepore void *pr, *pw;
864 66660095SIan Lepore
865 66660095SIan Lepore pr = NULL;
866 66660095SIan Lepore
867 66660095SIan Lepore pw = prep_write_buffer(popt);
868 66660095SIan Lepore icount = popt->count + popt->ncmd; /* assign after fn call */
869 66660095SIan Lepore
870 66660095SIan Lepore if (!pw) {
871 66660095SIan Lepore err = -1;
872 66660095SIan Lepore goto the_end;
873 66660095SIan Lepore }
874 66660095SIan Lepore
875 66660095SIan Lepore pr = malloc(icount + 1);
876 66660095SIan Lepore
877 66660095SIan Lepore if (!pr) {
878 66660095SIan Lepore err = -2;
879 66660095SIan Lepore goto the_end;
880 66660095SIan Lepore }
881 66660095SIan Lepore
882 66660095SIan Lepore bzero(pr, icount);
883 66660095SIan Lepore
884 66660095SIan Lepore err = _read_write(hdev, pw, pr, icount, popt->lsb);
885 66660095SIan Lepore
886 66660095SIan Lepore if (!err)
887 66660095SIan Lepore err = _do_data_output(pr, popt);
888 66660095SIan Lepore
889 66660095SIan Lepore the_end:
890 66660095SIan Lepore
891 66660095SIan Lepore free(pr);
892 66660095SIan Lepore free(pw);
893 66660095SIan Lepore
894 66660095SIan Lepore return err;
895 66660095SIan Lepore }
896 66660095SIan Lepore
897 66660095SIan Lepore
898 66660095SIan Lepore static void
verbose_dump_buffer(void * pbuf,int icount,int lsb)899 66660095SIan Lepore verbose_dump_buffer(void *pbuf, int icount, int lsb)
900 66660095SIan Lepore {
901 66660095SIan Lepore uint8_t ch;
902 *917d1846SIan Lepore int ictr, ictr2, idx;
903 66660095SIan Lepore
904 66660095SIan Lepore fputs(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F "
905 66660095SIan Lepore "| |\n", stderr);
906 66660095SIan Lepore
907 66660095SIan Lepore for (ictr = 0; ictr < icount; ictr += 16) {
908 66660095SIan Lepore fprintf(stderr, " %6x | ", ictr & 0xfffff0);
909 66660095SIan Lepore
910 66660095SIan Lepore for (ictr2 = 0; ictr2 < 16; ictr2++) {
911 *917d1846SIan Lepore idx = ictr + ictr2;
912 66660095SIan Lepore
913 *917d1846SIan Lepore if (idx < icount) {
914 *917d1846SIan Lepore ch = ((uint8_t *) pbuf)[idx];
915 66660095SIan Lepore
916 66660095SIan Lepore if (lsb)
917 66660095SIan Lepore ch = reversebits[ch];
918 66660095SIan Lepore
919 66660095SIan Lepore fprintf(stderr, "%02hhx ", ch);
920 66660095SIan Lepore }
921 66660095SIan Lepore else {
922 66660095SIan Lepore fputs(" ", stderr);
923 66660095SIan Lepore }
924 66660095SIan Lepore }
925 66660095SIan Lepore
926 66660095SIan Lepore fputs("| ", stderr);
927 66660095SIan Lepore
928 66660095SIan Lepore for (ictr2 = 0; ictr2 < 16; ictr2++) {
929 *917d1846SIan Lepore idx = ictr + ictr2;
930 66660095SIan Lepore
931 *917d1846SIan Lepore if (idx < icount) {
932 *917d1846SIan Lepore ch = ((uint8_t *) pbuf)[idx];
933 66660095SIan Lepore
934 66660095SIan Lepore if (lsb)
935 66660095SIan Lepore ch = reversebits[ch];
936 66660095SIan Lepore
937 66660095SIan Lepore if (ch < ' ' || ch > 127)
938 66660095SIan Lepore goto out_of_range;
939 66660095SIan Lepore
940 66660095SIan Lepore fprintf(stderr, "%c", ch);
941 66660095SIan Lepore }
942 *917d1846SIan Lepore else if (idx < icount) {
943 66660095SIan Lepore out_of_range:
944 66660095SIan Lepore fputc('.', stderr);
945 66660095SIan Lepore }
946 66660095SIan Lepore else {
947 66660095SIan Lepore fputc(' ', stderr);
948 66660095SIan Lepore }
949 66660095SIan Lepore }
950 66660095SIan Lepore
951 66660095SIan Lepore fputs(" |\n", stderr);
952 66660095SIan Lepore }
953 66660095SIan Lepore
954 66660095SIan Lepore fflush(stderr);
955 66660095SIan Lepore }
956