aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/spi/spidev_test.c115
-rw-r--r--drivers/spi/spidev.c55
2 files changed, 138 insertions, 32 deletions
diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c
index 3a2f9d59edab..94f574b0fdb2 100644
--- a/Documentation/spi/spidev_test.c
+++ b/Documentation/spi/spidev_test.c
@@ -15,6 +15,7 @@
15#include <unistd.h> 15#include <unistd.h>
16#include <stdio.h> 16#include <stdio.h>
17#include <stdlib.h> 17#include <stdlib.h>
18#include <string.h>
18#include <getopt.h> 19#include <getopt.h>
19#include <fcntl.h> 20#include <fcntl.h>
20#include <sys/ioctl.h> 21#include <sys/ioctl.h>
@@ -34,24 +35,79 @@ static uint32_t mode;
34static uint8_t bits = 8; 35static uint8_t bits = 8;
35static uint32_t speed = 500000; 36static uint32_t speed = 500000;
36static uint16_t delay; 37static uint16_t delay;
38static int verbose;
37 39
38static void transfer(int fd) 40uint8_t default_tx[] = {
41 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
42 0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
43 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
44 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
45 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
46 0xF0, 0x0D,
47};
48
49uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
50char *input_tx;
51
52static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix)
53{
54 int i = 0;
55 const unsigned char *address = src;
56 const unsigned char *line = address;
57 unsigned char c;
58
59 printf("%s | ", prefix);
60 while (length-- > 0) {
61 printf("%02X ", *address++);
62 if (!(++i % line_size) || (length == 0 && i % line_size)) {
63 if (length == 0) {
64 while (i++ % line_size)
65 printf("__ ");
66 }
67 printf(" | "); /* right close */
68 while (line < address) {
69 c = *line++;
70 printf("%c", (c < 33 || c == 255) ? 0x2E : c);
71 }
72 printf("\n");
73 if (length > 0)
74 printf("%s | ", prefix);
75 }
76 }
77}
78
79/*
80 * Unescape - process hexadecimal escape character
81 * converts shell input "\x23" -> 0x23
82 */
83int unespcape(char *_dst, char *_src, size_t len)
84{
85 int ret = 0;
86 char *src = _src;
87 char *dst = _dst;
88 unsigned int ch;
89
90 while (*src) {
91 if (*src == '\\' && *(src+1) == 'x') {
92 sscanf(src + 2, "%2x", &ch);
93 src += 4;
94 *dst++ = (unsigned char)ch;
95 } else {
96 *dst++ = *src++;
97 }
98 ret++;
99 }
100 return ret;
101}
102
103static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
39{ 104{
40 int ret; 105 int ret;
41 uint8_t tx[] = { 106
42 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
43 0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
44 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
45 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
46 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
47 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
48 0xF0, 0x0D,
49 };
50 uint8_t rx[ARRAY_SIZE(tx)] = {0, };
51 struct spi_ioc_transfer tr = { 107 struct spi_ioc_transfer tr = {
52 .tx_buf = (unsigned long)tx, 108 .tx_buf = (unsigned long)tx,
53 .rx_buf = (unsigned long)rx, 109 .rx_buf = (unsigned long)rx,
54 .len = ARRAY_SIZE(tx), 110 .len = len,
55 .delay_usecs = delay, 111 .delay_usecs = delay,
56 .speed_hz = speed, 112 .speed_hz = speed,
57 .bits_per_word = bits, 113 .bits_per_word = bits,
@@ -76,12 +132,9 @@ static void transfer(int fd)
76 if (ret < 1) 132 if (ret < 1)
77 pabort("can't send spi message"); 133 pabort("can't send spi message");
78 134
79 for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { 135 if (verbose)
80 if (!(ret % 6)) 136 hex_dump(tx, len, 32, "TX");
81 puts(""); 137 hex_dump(rx, len, 32, "RX");
82 printf("%.2X ", rx[ret]);
83 }
84 puts("");
85} 138}
86 139
87static void print_usage(const char *prog) 140static void print_usage(const char *prog)
@@ -97,6 +150,8 @@ static void print_usage(const char *prog)
97 " -L --lsb least significant bit first\n" 150 " -L --lsb least significant bit first\n"
98 " -C --cs-high chip select active high\n" 151 " -C --cs-high chip select active high\n"
99 " -3 --3wire SI/SO signals shared\n" 152 " -3 --3wire SI/SO signals shared\n"
153 " -v --verbose Verbose (show tx buffer)\n"
154 " -p Send data (e.g. \"1234\\xde\\xad\")\n"
100 " -N --no-cs no chip select\n" 155 " -N --no-cs no chip select\n"
101 " -R --ready slave pulls low to pause\n" 156 " -R --ready slave pulls low to pause\n"
102 " -2 --dual dual transfer\n" 157 " -2 --dual dual transfer\n"
@@ -121,12 +176,13 @@ static void parse_opts(int argc, char *argv[])
121 { "no-cs", 0, 0, 'N' }, 176 { "no-cs", 0, 0, 'N' },
122 { "ready", 0, 0, 'R' }, 177 { "ready", 0, 0, 'R' },
123 { "dual", 0, 0, '2' }, 178 { "dual", 0, 0, '2' },
179 { "verbose", 0, 0, 'v' },
124 { "quad", 0, 0, '4' }, 180 { "quad", 0, 0, '4' },
125 { NULL, 0, 0, 0 }, 181 { NULL, 0, 0, 0 },
126 }; 182 };
127 int c; 183 int c;
128 184
129 c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL); 185 c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24p:v", lopts, NULL);
130 186
131 if (c == -1) 187 if (c == -1)
132 break; 188 break;
@@ -165,9 +221,15 @@ static void parse_opts(int argc, char *argv[])
165 case 'N': 221 case 'N':
166 mode |= SPI_NO_CS; 222 mode |= SPI_NO_CS;
167 break; 223 break;
224 case 'v':
225 verbose = 1;
226 break;
168 case 'R': 227 case 'R':
169 mode |= SPI_READY; 228 mode |= SPI_READY;
170 break; 229 break;
230 case 'p':
231 input_tx = optarg;
232 break;
171 case '2': 233 case '2':
172 mode |= SPI_TX_DUAL; 234 mode |= SPI_TX_DUAL;
173 break; 235 break;
@@ -191,6 +253,9 @@ int main(int argc, char *argv[])
191{ 253{
192 int ret = 0; 254 int ret = 0;
193 int fd; 255 int fd;
256 uint8_t *tx;
257 uint8_t *rx;
258 int size;
194 259
195 parse_opts(argc, argv); 260 parse_opts(argc, argv);
196 261
@@ -235,7 +300,17 @@ int main(int argc, char *argv[])
235 printf("bits per word: %d\n", bits); 300 printf("bits per word: %d\n", bits);
236 printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 301 printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
237 302
238 transfer(fd); 303 if (input_tx) {
304 size = strlen(input_tx+1);
305 tx = malloc(size);
306 rx = malloc(size);
307 size = unespcape((char *)tx, input_tx, size);
308 transfer(fd, tx, rx, size);
309 free(rx);
310 free(tx);
311 } else {
312 transfer(fd, default_tx, default_rx, sizeof(default_tx));
313 }
239 314
240 close(fd); 315 close(fd);
241 316
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 4eb7a980e670..92c909eed6b5 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -223,7 +223,7 @@ static int spidev_message(struct spidev_data *spidev,
223 struct spi_transfer *k_xfers; 223 struct spi_transfer *k_xfers;
224 struct spi_transfer *k_tmp; 224 struct spi_transfer *k_tmp;
225 struct spi_ioc_transfer *u_tmp; 225 struct spi_ioc_transfer *u_tmp;
226 unsigned n, total; 226 unsigned n, total, tx_total, rx_total;
227 u8 *tx_buf, *rx_buf; 227 u8 *tx_buf, *rx_buf;
228 int status = -EFAULT; 228 int status = -EFAULT;
229 229
@@ -239,33 +239,52 @@ static int spidev_message(struct spidev_data *spidev,
239 tx_buf = spidev->tx_buffer; 239 tx_buf = spidev->tx_buffer;
240 rx_buf = spidev->rx_buffer; 240 rx_buf = spidev->rx_buffer;
241 total = 0; 241 total = 0;
242 tx_total = 0;
243 rx_total = 0;
242 for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; 244 for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
243 n; 245 n;
244 n--, k_tmp++, u_tmp++) { 246 n--, k_tmp++, u_tmp++) {
245 k_tmp->len = u_tmp->len; 247 k_tmp->len = u_tmp->len;
246 248
247 total += k_tmp->len; 249 total += k_tmp->len;
248 if (total > bufsiz) { 250 /* Since the function returns the total length of transfers
251 * on success, restrict the total to positive int values to
252 * avoid the return value looking like an error. Also check
253 * each transfer length to avoid arithmetic overflow.
254 */
255 if (total > INT_MAX || k_tmp->len > INT_MAX) {
249 status = -EMSGSIZE; 256 status = -EMSGSIZE;
250 goto done; 257 goto done;
251 } 258 }
252 259
253 if (u_tmp->rx_buf) { 260 if (u_tmp->rx_buf) {
261 /* this transfer needs space in RX bounce buffer */
262 rx_total += k_tmp->len;
263 if (rx_total > bufsiz) {
264 status = -EMSGSIZE;
265 goto done;
266 }
254 k_tmp->rx_buf = rx_buf; 267 k_tmp->rx_buf = rx_buf;
255 if (!access_ok(VERIFY_WRITE, (u8 __user *) 268 if (!access_ok(VERIFY_WRITE, (u8 __user *)
256 (uintptr_t) u_tmp->rx_buf, 269 (uintptr_t) u_tmp->rx_buf,
257 u_tmp->len)) 270 u_tmp->len))
258 goto done; 271 goto done;
272 rx_buf += k_tmp->len;
259 } 273 }
260 if (u_tmp->tx_buf) { 274 if (u_tmp->tx_buf) {
275 /* this transfer needs space in TX bounce buffer */
276 tx_total += k_tmp->len;
277 if (tx_total > bufsiz) {
278 status = -EMSGSIZE;
279 goto done;
280 }
261 k_tmp->tx_buf = tx_buf; 281 k_tmp->tx_buf = tx_buf;
262 if (copy_from_user(tx_buf, (const u8 __user *) 282 if (copy_from_user(tx_buf, (const u8 __user *)
263 (uintptr_t) u_tmp->tx_buf, 283 (uintptr_t) u_tmp->tx_buf,
264 u_tmp->len)) 284 u_tmp->len))
265 goto done; 285 goto done;
286 tx_buf += k_tmp->len;
266 } 287 }
267 tx_buf += k_tmp->len;
268 rx_buf += k_tmp->len;
269 288
270 k_tmp->cs_change = !!u_tmp->cs_change; 289 k_tmp->cs_change = !!u_tmp->cs_change;
271 k_tmp->tx_nbits = u_tmp->tx_nbits; 290 k_tmp->tx_nbits = u_tmp->tx_nbits;
@@ -303,8 +322,8 @@ static int spidev_message(struct spidev_data *spidev,
303 status = -EFAULT; 322 status = -EFAULT;
304 goto done; 323 goto done;
305 } 324 }
325 rx_buf += u_tmp->len;
306 } 326 }
307 rx_buf += u_tmp->len;
308 } 327 }
309 status = total; 328 status = total;
310 329
@@ -684,6 +703,14 @@ static const struct file_operations spidev_fops = {
684 703
685static struct class *spidev_class; 704static struct class *spidev_class;
686 705
706#ifdef CONFIG_OF
707static const struct of_device_id spidev_dt_ids[] = {
708 { .compatible = "rohm,dh2228fv" },
709 {},
710};
711MODULE_DEVICE_TABLE(of, spidev_dt_ids);
712#endif
713
687/*-------------------------------------------------------------------------*/ 714/*-------------------------------------------------------------------------*/
688 715
689static int spidev_probe(struct spi_device *spi) 716static int spidev_probe(struct spi_device *spi)
@@ -692,6 +719,17 @@ static int spidev_probe(struct spi_device *spi)
692 int status; 719 int status;
693 unsigned long minor; 720 unsigned long minor;
694 721
722 /*
723 * spidev should never be referenced in DT without a specific
724 * compatbile string, it is a Linux implementation thing
725 * rather than a description of the hardware.
726 */
727 if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
728 dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
729 WARN_ON(spi->dev.of_node &&
730 !of_match_device(spidev_dt_ids, &spi->dev));
731 }
732
695 /* Allocate driver data */ 733 /* Allocate driver data */
696 spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); 734 spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
697 if (!spidev) 735 if (!spidev)
@@ -758,13 +796,6 @@ static int spidev_remove(struct spi_device *spi)
758 return 0; 796 return 0;
759} 797}
760 798
761static const struct of_device_id spidev_dt_ids[] = {
762 { .compatible = "rohm,dh2228fv" },
763 {},
764};
765
766MODULE_DEVICE_TABLE(of, spidev_dt_ids);
767
768static struct spi_driver spidev_spi_driver = { 799static struct spi_driver spidev_spi_driver = {
769 .driver = { 800 .driver = {
770 .name = "spidev", 801 .name = "spidev",