diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-13 14:38:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-13 14:38:27 -0500 |
commit | 50ae833e471fe1a1a906a0342bdaa690e69fcc19 (patch) | |
tree | 15f4871eff7574f5677ce80a4faa2bf865d733d8 /tools | |
parent | ac53b2e053fffc74372da94e734b92f37e70d32c (diff) | |
parent | cabeea980879c2c701b0bd03f145c9f7dae17a63 (diff) |
Merge tag 'spi-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"A quiet release for SPI, not even many driver updates:
- Add a dummy loopback driver for use in exercising framework
features during development.
- Move the test utilities to tools/ and add support for transferring
data to and from a file instead of stdin and stdout to spidev_test.
- Support for Mediatek MT2701 and Renesas AG5 deices"
* tag 'spi-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (69 commits)
spi: loopback: fix typo in MODULE_PARM_DESC
spi: sun4i: Prevent chip-select from being activated twice before a transfer
spi: loopback-test: spi_check_rx_ranges can get always done
spi: loopback-test: rename method spi_test_fill_tx to spi_test_fill_pattern
spi: loopback-test: write rx pattern also when running without tx_buf
spi: fsl-espi: expose maximum transfer size limit
spi: expose master transfer size limitation.
spi: zynq: use to_platform_device()
spi: cadence: use to_platform_device()
spi: mediatek: Add spi support for mt2701 IC
spi: mediatek: merge all identical compat to mtk_common_compat
spi: mtk: Add bindings for mediatek MT2701 soc platform
spi: mediatek: Prevent overflows in FIFO transfers
spi: s3c64xx: Remove unused platform_device_id entries
spi: use to_spi_device
spi: dw: Use SPI_TMOD_TR rather than magic const 0 to set tmode
spi: imx: defer spi initialization, if DMA engine is
spi: imx: return error from dma channel request
spi: imx: enable loopback only for ECSPI controller family
spi: imx: fix loopback mode setup after controller reset
...
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile | 7 | ||||
-rw-r--r-- | tools/spi/.gitignore | 2 | ||||
-rw-r--r-- | tools/spi/Makefile | 4 | ||||
-rw-r--r-- | tools/spi/spidev_fdx.c | 158 | ||||
-rw-r--r-- | tools/spi/spidev_test.c | 399 |
5 files changed, 567 insertions, 3 deletions
diff --git a/tools/Makefile b/tools/Makefile index 0ba0df3b516f..1dc6900468ed 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -17,6 +17,7 @@ help: | |||
17 | @echo ' lguest - a minimal 32-bit x86 hypervisor' | 17 | @echo ' lguest - a minimal 32-bit x86 hypervisor' |
18 | @echo ' perf - Linux performance measurement and analysis tool' | 18 | @echo ' perf - Linux performance measurement and analysis tool' |
19 | @echo ' selftests - various kernel selftests' | 19 | @echo ' selftests - various kernel selftests' |
20 | @echo ' spi - spi tools' | ||
20 | @echo ' turbostat - Intel CPU idle stats and freq reporting tool' | 21 | @echo ' turbostat - Intel CPU idle stats and freq reporting tool' |
21 | @echo ' usb - USB testing tools' | 22 | @echo ' usb - USB testing tools' |
22 | @echo ' virtio - vhost test module' | 23 | @echo ' virtio - vhost test module' |
@@ -52,7 +53,7 @@ acpi: FORCE | |||
52 | cpupower: FORCE | 53 | cpupower: FORCE |
53 | $(call descend,power/$@) | 54 | $(call descend,power/$@) |
54 | 55 | ||
55 | cgroup firewire hv guest usb virtio vm net iio: FORCE | 56 | cgroup firewire hv guest spi usb virtio vm net iio: FORCE |
56 | $(call descend,$@) | 57 | $(call descend,$@) |
57 | 58 | ||
58 | liblockdep: FORCE | 59 | liblockdep: FORCE |
@@ -118,7 +119,7 @@ acpi_clean: | |||
118 | cpupower_clean: | 119 | cpupower_clean: |
119 | $(call descend,power/cpupower,clean) | 120 | $(call descend,power/cpupower,clean) |
120 | 121 | ||
121 | cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean iio_clean: | 122 | cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean: |
122 | $(call descend,$(@:_clean=),clean) | 123 | $(call descend,$(@:_clean=),clean) |
123 | 124 | ||
124 | liblockdep_clean: | 125 | liblockdep_clean: |
@@ -143,7 +144,7 @@ freefall_clean: | |||
143 | $(call descend,laptop/freefall,clean) | 144 | $(call descend,laptop/freefall,clean) |
144 | 145 | ||
145 | clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ | 146 | clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ |
146 | perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \ | 147 | perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ |
147 | vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ | 148 | vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ |
148 | freefall_clean | 149 | freefall_clean |
149 | 150 | ||
diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore new file mode 100644 index 000000000000..4280576397e8 --- /dev/null +++ b/tools/spi/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | spidev_fdx | ||
2 | spidev_test | ||
diff --git a/tools/spi/Makefile b/tools/spi/Makefile new file mode 100644 index 000000000000..cd0db62e4d9d --- /dev/null +++ b/tools/spi/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | all: spidev_test spidev_fdx | ||
2 | |||
3 | clean: | ||
4 | $(RM) spidev_test spidev_fdx | ||
diff --git a/tools/spi/spidev_fdx.c b/tools/spi/spidev_fdx.c new file mode 100644 index 000000000000..0ea3e51292fc --- /dev/null +++ b/tools/spi/spidev_fdx.c | |||
@@ -0,0 +1,158 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #include <sys/ioctl.h> | ||
8 | #include <sys/types.h> | ||
9 | #include <sys/stat.h> | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | #include <linux/spi/spidev.h> | ||
13 | |||
14 | |||
15 | static int verbose; | ||
16 | |||
17 | static void do_read(int fd, int len) | ||
18 | { | ||
19 | unsigned char buf[32], *bp; | ||
20 | int status; | ||
21 | |||
22 | /* read at least 2 bytes, no more than 32 */ | ||
23 | if (len < 2) | ||
24 | len = 2; | ||
25 | else if (len > sizeof(buf)) | ||
26 | len = sizeof(buf); | ||
27 | memset(buf, 0, sizeof buf); | ||
28 | |||
29 | status = read(fd, buf, len); | ||
30 | if (status < 0) { | ||
31 | perror("read"); | ||
32 | return; | ||
33 | } | ||
34 | if (status != len) { | ||
35 | fprintf(stderr, "short read\n"); | ||
36 | return; | ||
37 | } | ||
38 | |||
39 | printf("read(%2d, %2d): %02x %02x,", len, status, | ||
40 | buf[0], buf[1]); | ||
41 | status -= 2; | ||
42 | bp = buf + 2; | ||
43 | while (status-- > 0) | ||
44 | printf(" %02x", *bp++); | ||
45 | printf("\n"); | ||
46 | } | ||
47 | |||
48 | static void do_msg(int fd, int len) | ||
49 | { | ||
50 | struct spi_ioc_transfer xfer[2]; | ||
51 | unsigned char buf[32], *bp; | ||
52 | int status; | ||
53 | |||
54 | memset(xfer, 0, sizeof xfer); | ||
55 | memset(buf, 0, sizeof buf); | ||
56 | |||
57 | if (len > sizeof buf) | ||
58 | len = sizeof buf; | ||
59 | |||
60 | buf[0] = 0xaa; | ||
61 | xfer[0].tx_buf = (unsigned long)buf; | ||
62 | xfer[0].len = 1; | ||
63 | |||
64 | xfer[1].rx_buf = (unsigned long) buf; | ||
65 | xfer[1].len = len; | ||
66 | |||
67 | status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer); | ||
68 | if (status < 0) { | ||
69 | perror("SPI_IOC_MESSAGE"); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | printf("response(%2d, %2d): ", len, status); | ||
74 | for (bp = buf; len; len--) | ||
75 | printf(" %02x", *bp++); | ||
76 | printf("\n"); | ||
77 | } | ||
78 | |||
79 | static void dumpstat(const char *name, int fd) | ||
80 | { | ||
81 | __u8 lsb, bits; | ||
82 | __u32 mode, speed; | ||
83 | |||
84 | if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) { | ||
85 | perror("SPI rd_mode"); | ||
86 | return; | ||
87 | } | ||
88 | if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) { | ||
89 | perror("SPI rd_lsb_fist"); | ||
90 | return; | ||
91 | } | ||
92 | if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) { | ||
93 | perror("SPI bits_per_word"); | ||
94 | return; | ||
95 | } | ||
96 | if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) { | ||
97 | perror("SPI max_speed_hz"); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n", | ||
102 | name, mode, bits, lsb ? "(lsb first) " : "", speed); | ||
103 | } | ||
104 | |||
105 | int main(int argc, char **argv) | ||
106 | { | ||
107 | int c; | ||
108 | int readcount = 0; | ||
109 | int msglen = 0; | ||
110 | int fd; | ||
111 | const char *name; | ||
112 | |||
113 | while ((c = getopt(argc, argv, "hm:r:v")) != EOF) { | ||
114 | switch (c) { | ||
115 | case 'm': | ||
116 | msglen = atoi(optarg); | ||
117 | if (msglen < 0) | ||
118 | goto usage; | ||
119 | continue; | ||
120 | case 'r': | ||
121 | readcount = atoi(optarg); | ||
122 | if (readcount < 0) | ||
123 | goto usage; | ||
124 | continue; | ||
125 | case 'v': | ||
126 | verbose++; | ||
127 | continue; | ||
128 | case 'h': | ||
129 | case '?': | ||
130 | usage: | ||
131 | fprintf(stderr, | ||
132 | "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n", | ||
133 | argv[0]); | ||
134 | return 1; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | if ((optind + 1) != argc) | ||
139 | goto usage; | ||
140 | name = argv[optind]; | ||
141 | |||
142 | fd = open(name, O_RDWR); | ||
143 | if (fd < 0) { | ||
144 | perror("open"); | ||
145 | return 1; | ||
146 | } | ||
147 | |||
148 | dumpstat(name, fd); | ||
149 | |||
150 | if (msglen) | ||
151 | do_msg(fd, msglen); | ||
152 | |||
153 | if (readcount) | ||
154 | do_read(fd, readcount); | ||
155 | |||
156 | close(fd); | ||
157 | return 0; | ||
158 | } | ||
diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c new file mode 100644 index 000000000000..8a73d8185316 --- /dev/null +++ b/tools/spi/spidev_test.c | |||
@@ -0,0 +1,399 @@ | |||
1 | /* | ||
2 | * SPI testing utility (using spidev driver) | ||
3 | * | ||
4 | * Copyright (c) 2007 MontaVista Software, Inc. | ||
5 | * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License. | ||
10 | * | ||
11 | * Cross-compile with cross-gcc -I/path/to/cross-kernel/include | ||
12 | */ | ||
13 | |||
14 | #include <stdint.h> | ||
15 | #include <unistd.h> | ||
16 | #include <stdio.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | #include <getopt.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <sys/ioctl.h> | ||
22 | #include <sys/stat.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/spi/spidev.h> | ||
25 | |||
26 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) | ||
27 | |||
28 | static void pabort(const char *s) | ||
29 | { | ||
30 | perror(s); | ||
31 | abort(); | ||
32 | } | ||
33 | |||
34 | static const char *device = "/dev/spidev1.1"; | ||
35 | static uint32_t mode; | ||
36 | static uint8_t bits = 8; | ||
37 | static char *input_file; | ||
38 | static char *output_file; | ||
39 | static uint32_t speed = 500000; | ||
40 | static uint16_t delay; | ||
41 | static int verbose; | ||
42 | |||
43 | uint8_t default_tx[] = { | ||
44 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
45 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, | ||
46 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
47 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
48 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
49 | 0xF0, 0x0D, | ||
50 | }; | ||
51 | |||
52 | uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, }; | ||
53 | char *input_tx; | ||
54 | |||
55 | static void hex_dump(const void *src, size_t length, size_t line_size, | ||
56 | char *prefix) | ||
57 | { | ||
58 | int i = 0; | ||
59 | const unsigned char *address = src; | ||
60 | const unsigned char *line = address; | ||
61 | unsigned char c; | ||
62 | |||
63 | printf("%s | ", prefix); | ||
64 | while (length-- > 0) { | ||
65 | printf("%02X ", *address++); | ||
66 | if (!(++i % line_size) || (length == 0 && i % line_size)) { | ||
67 | if (length == 0) { | ||
68 | while (i++ % line_size) | ||
69 | printf("__ "); | ||
70 | } | ||
71 | printf(" | "); /* right close */ | ||
72 | while (line < address) { | ||
73 | c = *line++; | ||
74 | printf("%c", (c < 33 || c == 255) ? 0x2E : c); | ||
75 | } | ||
76 | printf("\n"); | ||
77 | if (length > 0) | ||
78 | printf("%s | ", prefix); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Unescape - process hexadecimal escape character | ||
85 | * converts shell input "\x23" -> 0x23 | ||
86 | */ | ||
87 | static int unescape(char *_dst, char *_src, size_t len) | ||
88 | { | ||
89 | int ret = 0; | ||
90 | int match; | ||
91 | char *src = _src; | ||
92 | char *dst = _dst; | ||
93 | unsigned int ch; | ||
94 | |||
95 | while (*src) { | ||
96 | if (*src == '\\' && *(src+1) == 'x') { | ||
97 | match = sscanf(src + 2, "%2x", &ch); | ||
98 | if (!match) | ||
99 | pabort("malformed input string"); | ||
100 | |||
101 | src += 4; | ||
102 | *dst++ = (unsigned char)ch; | ||
103 | } else { | ||
104 | *dst++ = *src++; | ||
105 | } | ||
106 | ret++; | ||
107 | } | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) | ||
112 | { | ||
113 | int ret; | ||
114 | int out_fd; | ||
115 | struct spi_ioc_transfer tr = { | ||
116 | .tx_buf = (unsigned long)tx, | ||
117 | .rx_buf = (unsigned long)rx, | ||
118 | .len = len, | ||
119 | .delay_usecs = delay, | ||
120 | .speed_hz = speed, | ||
121 | .bits_per_word = bits, | ||
122 | }; | ||
123 | |||
124 | if (mode & SPI_TX_QUAD) | ||
125 | tr.tx_nbits = 4; | ||
126 | else if (mode & SPI_TX_DUAL) | ||
127 | tr.tx_nbits = 2; | ||
128 | if (mode & SPI_RX_QUAD) | ||
129 | tr.rx_nbits = 4; | ||
130 | else if (mode & SPI_RX_DUAL) | ||
131 | tr.rx_nbits = 2; | ||
132 | if (!(mode & SPI_LOOP)) { | ||
133 | if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) | ||
134 | tr.rx_buf = 0; | ||
135 | else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) | ||
136 | tr.tx_buf = 0; | ||
137 | } | ||
138 | |||
139 | ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); | ||
140 | if (ret < 1) | ||
141 | pabort("can't send spi message"); | ||
142 | |||
143 | if (verbose) | ||
144 | hex_dump(tx, len, 32, "TX"); | ||
145 | |||
146 | if (output_file) { | ||
147 | out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); | ||
148 | if (out_fd < 0) | ||
149 | pabort("could not open output file"); | ||
150 | |||
151 | ret = write(out_fd, rx, len); | ||
152 | if (ret != len) | ||
153 | pabort("not all bytes written to output file"); | ||
154 | |||
155 | close(out_fd); | ||
156 | } | ||
157 | |||
158 | if (verbose || !output_file) | ||
159 | hex_dump(rx, len, 32, "RX"); | ||
160 | } | ||
161 | |||
162 | static void print_usage(const char *prog) | ||
163 | { | ||
164 | printf("Usage: %s [-DsbdlHOLC3]\n", prog); | ||
165 | puts(" -D --device device to use (default /dev/spidev1.1)\n" | ||
166 | " -s --speed max speed (Hz)\n" | ||
167 | " -d --delay delay (usec)\n" | ||
168 | " -b --bpw bits per word\n" | ||
169 | " -i --input input data from a file (e.g. \"test.bin\")\n" | ||
170 | " -o --output output data to a file (e.g. \"results.bin\")\n" | ||
171 | " -l --loop loopback\n" | ||
172 | " -H --cpha clock phase\n" | ||
173 | " -O --cpol clock polarity\n" | ||
174 | " -L --lsb least significant bit first\n" | ||
175 | " -C --cs-high chip select active high\n" | ||
176 | " -3 --3wire SI/SO signals shared\n" | ||
177 | " -v --verbose Verbose (show tx buffer)\n" | ||
178 | " -p Send data (e.g. \"1234\\xde\\xad\")\n" | ||
179 | " -N --no-cs no chip select\n" | ||
180 | " -R --ready slave pulls low to pause\n" | ||
181 | " -2 --dual dual transfer\n" | ||
182 | " -4 --quad quad transfer\n"); | ||
183 | exit(1); | ||
184 | } | ||
185 | |||
186 | static void parse_opts(int argc, char *argv[]) | ||
187 | { | ||
188 | while (1) { | ||
189 | static const struct option lopts[] = { | ||
190 | { "device", 1, 0, 'D' }, | ||
191 | { "speed", 1, 0, 's' }, | ||
192 | { "delay", 1, 0, 'd' }, | ||
193 | { "bpw", 1, 0, 'b' }, | ||
194 | { "input", 1, 0, 'i' }, | ||
195 | { "output", 1, 0, 'o' }, | ||
196 | { "loop", 0, 0, 'l' }, | ||
197 | { "cpha", 0, 0, 'H' }, | ||
198 | { "cpol", 0, 0, 'O' }, | ||
199 | { "lsb", 0, 0, 'L' }, | ||
200 | { "cs-high", 0, 0, 'C' }, | ||
201 | { "3wire", 0, 0, '3' }, | ||
202 | { "no-cs", 0, 0, 'N' }, | ||
203 | { "ready", 0, 0, 'R' }, | ||
204 | { "dual", 0, 0, '2' }, | ||
205 | { "verbose", 0, 0, 'v' }, | ||
206 | { "quad", 0, 0, '4' }, | ||
207 | { NULL, 0, 0, 0 }, | ||
208 | }; | ||
209 | int c; | ||
210 | |||
211 | c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v", | ||
212 | lopts, NULL); | ||
213 | |||
214 | if (c == -1) | ||
215 | break; | ||
216 | |||
217 | switch (c) { | ||
218 | case 'D': | ||
219 | device = optarg; | ||
220 | break; | ||
221 | case 's': | ||
222 | speed = atoi(optarg); | ||
223 | break; | ||
224 | case 'd': | ||
225 | delay = atoi(optarg); | ||
226 | break; | ||
227 | case 'b': | ||
228 | bits = atoi(optarg); | ||
229 | break; | ||
230 | case 'i': | ||
231 | input_file = optarg; | ||
232 | break; | ||
233 | case 'o': | ||
234 | output_file = optarg; | ||
235 | break; | ||
236 | case 'l': | ||
237 | mode |= SPI_LOOP; | ||
238 | break; | ||
239 | case 'H': | ||
240 | mode |= SPI_CPHA; | ||
241 | break; | ||
242 | case 'O': | ||
243 | mode |= SPI_CPOL; | ||
244 | break; | ||
245 | case 'L': | ||
246 | mode |= SPI_LSB_FIRST; | ||
247 | break; | ||
248 | case 'C': | ||
249 | mode |= SPI_CS_HIGH; | ||
250 | break; | ||
251 | case '3': | ||
252 | mode |= SPI_3WIRE; | ||
253 | break; | ||
254 | case 'N': | ||
255 | mode |= SPI_NO_CS; | ||
256 | break; | ||
257 | case 'v': | ||
258 | verbose = 1; | ||
259 | break; | ||
260 | case 'R': | ||
261 | mode |= SPI_READY; | ||
262 | break; | ||
263 | case 'p': | ||
264 | input_tx = optarg; | ||
265 | break; | ||
266 | case '2': | ||
267 | mode |= SPI_TX_DUAL; | ||
268 | break; | ||
269 | case '4': | ||
270 | mode |= SPI_TX_QUAD; | ||
271 | break; | ||
272 | default: | ||
273 | print_usage(argv[0]); | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | if (mode & SPI_LOOP) { | ||
278 | if (mode & SPI_TX_DUAL) | ||
279 | mode |= SPI_RX_DUAL; | ||
280 | if (mode & SPI_TX_QUAD) | ||
281 | mode |= SPI_RX_QUAD; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void transfer_escaped_string(int fd, char *str) | ||
286 | { | ||
287 | size_t size = strlen(str + 1); | ||
288 | uint8_t *tx; | ||
289 | uint8_t *rx; | ||
290 | |||
291 | tx = malloc(size); | ||
292 | if (!tx) | ||
293 | pabort("can't allocate tx buffer"); | ||
294 | |||
295 | rx = malloc(size); | ||
296 | if (!rx) | ||
297 | pabort("can't allocate rx buffer"); | ||
298 | |||
299 | size = unescape((char *)tx, str, size); | ||
300 | transfer(fd, tx, rx, size); | ||
301 | free(rx); | ||
302 | free(tx); | ||
303 | } | ||
304 | |||
305 | static void transfer_file(int fd, char *filename) | ||
306 | { | ||
307 | ssize_t bytes; | ||
308 | struct stat sb; | ||
309 | int tx_fd; | ||
310 | uint8_t *tx; | ||
311 | uint8_t *rx; | ||
312 | |||
313 | if (stat(filename, &sb) == -1) | ||
314 | pabort("can't stat input file"); | ||
315 | |||
316 | tx_fd = open(filename, O_RDONLY); | ||
317 | if (fd < 0) | ||
318 | pabort("can't open input file"); | ||
319 | |||
320 | tx = malloc(sb.st_size); | ||
321 | if (!tx) | ||
322 | pabort("can't allocate tx buffer"); | ||
323 | |||
324 | rx = malloc(sb.st_size); | ||
325 | if (!rx) | ||
326 | pabort("can't allocate rx buffer"); | ||
327 | |||
328 | bytes = read(tx_fd, tx, sb.st_size); | ||
329 | if (bytes != sb.st_size) | ||
330 | pabort("failed to read input file"); | ||
331 | |||
332 | transfer(fd, tx, rx, sb.st_size); | ||
333 | free(rx); | ||
334 | free(tx); | ||
335 | close(tx_fd); | ||
336 | } | ||
337 | |||
338 | int main(int argc, char *argv[]) | ||
339 | { | ||
340 | int ret = 0; | ||
341 | int fd; | ||
342 | |||
343 | parse_opts(argc, argv); | ||
344 | |||
345 | fd = open(device, O_RDWR); | ||
346 | if (fd < 0) | ||
347 | pabort("can't open device"); | ||
348 | |||
349 | /* | ||
350 | * spi mode | ||
351 | */ | ||
352 | ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode); | ||
353 | if (ret == -1) | ||
354 | pabort("can't set spi mode"); | ||
355 | |||
356 | ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode); | ||
357 | if (ret == -1) | ||
358 | pabort("can't get spi mode"); | ||
359 | |||
360 | /* | ||
361 | * bits per word | ||
362 | */ | ||
363 | ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); | ||
364 | if (ret == -1) | ||
365 | pabort("can't set bits per word"); | ||
366 | |||
367 | ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); | ||
368 | if (ret == -1) | ||
369 | pabort("can't get bits per word"); | ||
370 | |||
371 | /* | ||
372 | * max speed hz | ||
373 | */ | ||
374 | ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); | ||
375 | if (ret == -1) | ||
376 | pabort("can't set max speed hz"); | ||
377 | |||
378 | ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); | ||
379 | if (ret == -1) | ||
380 | pabort("can't get max speed hz"); | ||
381 | |||
382 | printf("spi mode: 0x%x\n", mode); | ||
383 | printf("bits per word: %d\n", bits); | ||
384 | printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); | ||
385 | |||
386 | if (input_tx && input_file) | ||
387 | pabort("only one of -p and --input may be selected"); | ||
388 | |||
389 | if (input_tx) | ||
390 | transfer_escaped_string(fd, input_tx); | ||
391 | else if (input_file) | ||
392 | transfer_file(fd, input_file); | ||
393 | else | ||
394 | transfer(fd, default_tx, default_rx, sizeof(default_tx)); | ||
395 | |||
396 | close(fd); | ||
397 | |||
398 | return ret; | ||
399 | } | ||